Nano Banana 2(Gemini 3.1 Flash Image、モデルID gemini-3.1-flash-image-preview)で blockReason OTHER が返された場合、リクエストがGoogleのレイヤー2ポリシーフィルターによってブロックされたことを意味します。このフィルターはサーバーサイドで動作する設定不可のフィルターであり、セーフティしきい値をBLOCK_NONEやOFFに設定しても回避することはできません。2026年3月時点で、このフィルターは著作権キャラクター、公人、NSFWコンテンツを含む8つのコンテンツカテゴリをカバーしています。本ガイドでは、blockReasonとfinishReasonの完全マッピング、二層セーフティアーキテクチャの仕組み、そして実証済みの5つの解決策をプロダクション対応コード付きで解説します。
まとめ
- blockReason OTHER と blockReason SAFETY は別物です:OTHERはレイヤー2(設定不可のポリシー適用)から発生し、SAFETYはレイヤー1(
harm_block_thresholdで調整可能)から発生します。BLOCK_NONEやOFFを設定してもレイヤー1にしか影響せず、レイヤー2のブロックは解除できません。 - 8つのコンテンツカテゴリがblockReason OTHERをトリガーします:NSFWコンテンツ、著作権キャラクター/有名IP、公人、未成年者保護、ウォーターマーク除去、金融情報改変、衣服/顔スワップ、暗示的な性的コンテンツの8カテゴリです。2026年3月にこのうち4カテゴリの適用が厳格化されました。
- blockReasonとfinishReasonは異なるフィールドです:
blockReasonはプロンプトが生成開始前に拒否された場合に表示されます(トークン消費ゼロ)。finishReasonはコンテンツが生成中または生成後にブロックされた場合に表示されます(トークンが消費済み)。両方ともOTHER関連の値を返す可能性があります。 - python-genai SDKのバグに注意:ブロックされたレスポンスで
response.candidates[0].finish_reasonにアクセスすると、candidatesが空配列のため無限にハングします。必ず先にlen(response.candidates) > 0を確認してください。 - 5つの実証済み回避策があります:プロンプトの言い換え、著作権参照の除去、複雑なプロンプトの分割、タイムアウト付きモデルフォールバック、または代替画像モデル(GPT Image、FLUX.2)をフォールバックパイプラインとして使用する方法です。
blockReason OTHERの本当の意味とは

Nano Banana 2に画像生成リクエストを送信し、APIレスポンスで blockReason: "OTHER" を受け取った場合、プロンプトが画像生成開始前にGoogleの第2レイヤーのコンテンツフィルタリングによってインターセプトされたことを意味します。これは、セーフティ設定で制御可能な第1レイヤーのフィルタリングから返される blockReason: "SAFETY" とは根本的に異なります。この違いを理解することが、エラー解決への最も重要な第一歩です。なぜなら、設定変更で解決できる問題なのか、まったく別のアプローチが必要なのかが、この違いによって決まるからです。
blockReasonとfinishReasonの混同は、Gemini画像生成APIを扱う開発者にとって2番目に多いフラストレーションの原因です。この2つのフィールドはレスポンスの異なる部分に表示され、課金に対する影響も異なり、必要なトラブルシューティング戦略も異なります。以下の表は、これまで5つの別々の記事を読まなければ把握できなかった完全なマッピングをまとめたものです。
blockReasonの値(プロンプトレベルのブロック)
blockReason フィールドはAPIレスポンスの prompt_feedback セクションに表示されます。このフィールドが存在する場合、プロンプトが生成開始前に拒否されたことを意味し、トークンは消費されず、部分的な画像も存在しません。
| blockReasonの値 | ソースレイヤー | 設定可能? | 意味 |
|---|---|---|---|
SAFETY | レイヤー1 | はい(harm_block_threshold で調整可能) | 4つの有害カテゴリのいずれかが設定しきい値を超えました。BLOCK_NONE または OFF で解決できます。 |
OTHER | レイヤー2 | いいえ | サーバーサイドのポリシーがプロンプト内の禁止コンテンツを検出しました。回避不可能です。 |
BLOCKED_REASON_UNSPECIFIED | いずれか | 場合による | まれに発生するキャッチオール。セーフティレーティングとプロンプト内容の両方を確認してください。 |
blockReason OTHERのレスポンスを受け取った場合、JSONの構造は以下のようになります:
json{ "promptFeedback": { "blockReason": "OTHER" }, "candidates": [] }
candidates 配列が完全に空であることに注目してください。検査できるセーフティレーティングも、復元できる部分的なコンテンツも、どのポリシールールがブロックをトリガーしたかを示す具体的なカテゴリもありません。これは意図的な設計です。Googleのレイヤー2フィルターは、どのポリシールールに違反したかを意図的に公開しません。公開すると、悪意のあるユーザーが検出をぎりぎり回避するプロンプトを作成する手助けになりかねないためです。
finishReasonの値(生成レベルのブロック)
finishReason フィールドは各candidateオブジェクト内に表示され、生成が停止した理由を示します。blockReasonとは異なり、これらのブロックは生成中に発生するため、トークンはすでに消費されており、部分的なテキスト出力が表示される可能性があります(ただし、部分的な画像は表示されません)。
| finishReasonの値 | ソースレイヤー | 意味 |
|---|---|---|
STOP | N/A | 正常完了。画像の生成に成功しました。 |
SAFETY | レイヤー1 | 生成されたコンテンツが設定可能なセーフティフィルターをトリガーしました。設定で調整可能です。 |
IMAGE_SAFETY | レイヤー2 | 生成中に画像固有のセーフティ違反が検出されました。設定不可です。 |
OTHER | レイヤー2 | 著作権、商標、または有名IPが生成コンテンツで検出されました。設定不可です。 |
PROHIBITED_CONTENT | レイヤー2 | 児童の安全または法的に禁止されたコンテンツ。最も厳格な適用で、設定不可です。 |
重要な違いはタイミングです。blockReasonは生成前に発火します(コストなし)が、finishReasonは生成中に発火します(トークンを消費します)。blockReason: "OTHER" ではなく finishReason: "OTHER" が表示されている場合、プロンプトは初期フィルターを通過したものの、生成された画像が第2レイヤーで検出されたことを意味します。これは通常、画像合成中にのみ明らかになる著作権や商標コンテンツを示しています。たとえば、「丸い耳の漫画のネズミ」というプロンプトはプロンプトフィルターを通過するかもしれませんが、生成された画像が著作権キャラクターに似ていた場合に finishReason: OTHER がトリガーされます。
GitHub Issue #276で確認されている通り、Googleは児童の安全保護を含む必須フィルターは無効化できないと明言しており、レイヤー2のブロックにはプログラム的な回避策は存在しないとしています。これはバグではなく、意図的なアーキテクチャ上の決定です。
BLOCK_NONEでblockReason OTHERを解決できない理由

blockReason OTHERに遭遇した開発者が最もよく犯す間違いは、すぐにすべてのセーフティカテゴリを BLOCK_NONE や OFF に設定してエラーが解決されることを期待することです。このアプローチが失敗するのは、Geminiのセーフティフィルタリングアーキテクチャの仕組みを根本的に誤解しているためです。このシステムは完全に独立した2つのレイヤーで動作しており、セーフティ設定で制御できるのは最初のレイヤーのみです。利用可能なすべてのセーフティ設定についてさらに深く理解するには、Geminiセーフティ設定の詳細ガイドをご覧ください。
レイヤー1:設定可能なセーフティフィルター
レイヤー1は、個別に設定可能な4つの有害カテゴリに対してプロンプトと生成コンテンツを評価します:HARM_CATEGORY_HARASSMENT、HARM_CATEGORY_HATE_SPEECH、HARM_CATEGORY_SEXUALLY_EXPLICIT、HARM_CATEGORY_DANGEROUS_CONTENT の4つです。各カテゴリに対して harm_block_threshold を設定し、フィルターの感度を調整できます。レイヤー1のフィルターがトリガーされると、blockReason: "SAFETY" とともに詳細なセーフティレーティングが返され、どのカテゴリがどの信頼度レベルでトリガーされたかが正確にわかります。
レイヤー1の制御には2つのオプションがあります。しきい値を BLOCK_NONE に設定すると自動ブロックが無効になりますが、レスポンスにはセーフティメタデータが返され、モニタリングやログ記録に活用できます。しきい値を OFF に設定すると(gemini-2.5-flash以降のモデルで利用可能、2026年1月時点のVertex AIドキュメントに基づく)、ブロックとメタデータ収集の両方が完全に無効になります。Gemini 3.1 Flashをベースとする Nano Banana 2では、どちらのオプションも利用可能であり、いずれもレイヤー1のブロックを完全に排除します。
レイヤー1を最大限に許容的に設定する方法は以下の通りです:
pythonfrom google import genai from google.genai import types client = genai.Client(api_key="YOUR_API_KEY") safety_settings_block_none = [ types.SafetySetting( category="HARM_CATEGORY_HARASSMENT", threshold="BLOCK_NONE" ), types.SafetySetting( category="HARM_CATEGORY_HATE_SPEECH", threshold="BLOCK_NONE" ), types.SafetySetting( category="HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold="BLOCK_NONE" ), types.SafetySetting( category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_NONE" ), ] # Option 2: OFF - no blocking AND no safety metadata safety_settings_off = [ types.SafetySetting( category="HARM_CATEGORY_HARASSMENT", threshold="OFF" ), # ... same for other categories ]
レイヤー2:設定不可のポリシー適用
レイヤー2は、セーフティ設定とは完全に独立して動作する別個のシステムです。Googleのコンテンツポリシー、法的要件、利用規約をサーバーサイドのフィルターで適用しており、APIパラメータからアクセス、変更、回避することは一切できません。レイヤー2がトリガーされると、blockReason: "OTHER" が返されますが、セーフティレーティング、カテゴリ情報、どの具体的なポリシーに違反したかを特定する方法はいずれも提供されません。
レイヤー2は、一般的なセーフティの懸念を超えて法的責任の領域に踏み込むコンテンツカテゴリをカバーしています。児童の安全(ほとんどの法域で法的要件)、著作権キャラクターと商標のビジュアルアイデンティティ、特定可能な公人と有名人、Googleの利用規約に違反するNSFWコンテンツ、および次のセクションで詳述するその他のカテゴリです。これらのフィルターが存在する理由は、開発者の意図する使用目的にかかわらず、画像生成APIが特定の種類のコンテンツを生成した場合にGoogleが直接的な法的責任を負うためです。
実用上の意味は明確です。blockReason: "OTHER" を受け取っている場合、セーフティ設定をいくら変更しても効果はありません。4つのカテゴリすべてをBLOCK_NONEまたはOFFに設定してもブロックされることで、これは確認済みです。ブロックは制御可能なシステムからではなく、その背後にあるシステムから発生しています。唯一の前進方法は、プロンプトを修正するか、別のアプローチを使用することであり、以下のソリューションセクションで詳しく説明します。
ステップバイステップ診断フローチャート

Nano Banana 2のAPI呼び出しがエラーを返した場合、最初にすべきことはセーフティ設定の変更ではなく、どの種類のエラーに対処しているかを正確に特定することです。エラーの種類によって必要な解決策はまったく異なり、間違った修正を適用すると時間とAPIクォータを無駄にします。この診断フローチャートは、推測を排除する体系的なアプローチを提供します。
まず、レスポンスの prompt_feedback セクションに blockReason フィールドが含まれているかどうかを確認します。blockReasonが存在しない場合、問題はまったく別の種類のエラーである可能性があります。candidates配列に finishReason: "OTHER" がないか確認してください。これが存在する場合、プロンプトは初期フィルターを通過したものの、著作権や商標の問題により生成途中でコンテンツがブロックされたことを示しています。blockReasonもfinishReason OTHERも存在しない場合は、200 OKだが画像が生成されないシナリオや503 オーバーロードエラーの問題を扱っている可能性があり、それぞれ独自のトラブルシューティングパスが必要です。その他の一般的なNano Banana 2エラーについては、thoughtシグネチャエラーに関するガイドをご覧ください。
blockReasonが存在する場合は、その値を確認します。値が SAFETY であれば、セーフティ設定の構成で修正可能なレイヤー1のブロックに対処しています。レスポンスのセーフティレーティングを検査してトリガーされたカテゴリを特定し、そのカテゴリのしきい値を BLOCK_NONE または OFF に設定してください。値が OTHER であれば、レイヤー2のブロックが確認されたことになり、本ガイドのソリューションが適用されます。
以下は、このプロセスを自動化する診断コードです:
pythondef diagnose_block(response): """Systematically diagnose why a Nano Banana 2 request was blocked.""" # Step 1: Check for prompt-level blocking if hasattr(response, 'prompt_feedback') and response.prompt_feedback: block_reason = getattr(response.prompt_feedback, 'block_reason', None) if block_reason == 'SAFETY': # Layer 1 block - fixable via safety settings ratings = response.prompt_feedback.safety_ratings triggered = [r for r in ratings if r.blocked] return { 'type': 'LAYER_1_BLOCK', 'fixable': True, 'categories': [r.category for r in triggered], 'action': 'Set triggered categories to BLOCK_NONE or OFF' } elif block_reason == 'OTHER': # Layer 2 block - not fixable via settings return { 'type': 'LAYER_2_BLOCK', 'fixable': False, 'action': 'Rephrase prompt or use alternative model' } # Step 2: Check for generation-level blocking if len(response.candidates) > 0: finish_reason = response.candidates[0].finish_reason if finish_reason == 'OTHER': return { 'type': 'LAYER_2_GENERATION_BLOCK', 'fixable': False, 'action': 'Copyright/trademark detected during generation' } if finish_reason == 'IMAGE_SAFETY': return { 'type': 'IMAGE_SAFETY_BLOCK', 'fixable': False, 'action': 'Image content violated safety policy' } # Step 3: No candidates and no block reason if len(response.candidates) == 0: return { 'type': 'EMPTY_RESPONSE', 'fixable': False, 'action': 'Check for 200 OK no-image scenario' } return {'type': 'UNKNOWN', 'action': 'Inspect full response JSON'}
google-genai SDKを使用するPython開発者が注意すべき重要な点があります。candidates配列が空の状態で response.candidates[0].finish_reason にアクセスしようとすると、例外が発生する代わりにSDKが無限にハングします。これは2026年3月時点での既知のバグで、SDKがcandidateオブジェクトを遅延評価しようとして無限待機状態に入ります。candidateのプロパティにアクセスする前に、必ず len(response.candidates) > 0 を確認してください。このハングが発生した場合、回復方法はプロセスを強制終了するしかありません。
地域に関する注意事項
EU圏の開発者は、IPベースのポリシー適用により、他の地域では問題なく動作するプロンプトでもblockReason OTHERがトリガーされる可能性があることに注意してください。これは、AI生成画像に関するより厳格な規制がある法域に対して、Googleがより厳しいコンテンツポリシーを適用しているためです。地域によるブロックが疑われる場合は、同じプロンプトを別の地理的地域からテストすることで、ブロックがコンテンツベースか地域ベースかを確認できます。
blockReason OTHERをトリガーする8つのコンテンツカテゴリ
レイヤー2のブロックをトリガーするコンテンツを正確に理解することで、不必要な拒否を回避するプロンプトを作成できます。Googleの公式ドキュメント、コミュニティレポート、および複数のソースに文書化された体系的なテストを相互参照することで、Nano Banana 2で一貫してblockReason OTHERをトリガーする8つの異なるコンテンツカテゴリを特定しました。2026年3月時点で、Googleはこのうち4つのカテゴリの適用を厳格化しており、以前は動作していたプロンプトがブロックされるようになった理由を説明しています。
NSFWおよび性的に露骨なコンテンツは最も広範なカテゴリであり、ヌード、性行為、またはフェティッシュコンテンツを要求するあらゆるプロンプトをキャッチします。レイヤー1の HARM_CATEGORY_SEXUALLY_EXPLICIT はBLOCK_NONEに設定できますが、レイヤー2のNSFWフィルターは独立して動作し、無効にできません。これにより、BLOCK_NONEしきい値でレイヤー1が許可するはずのプロンプトもキャッチされ、セーフティ設定では「すべて許可」と設定しているにもかかわらずリクエストがブロックされるという紛らわしい状況が生じます。
著作権キャラクターと有名IPは、大手知的財産権者が所有するキャラクターをプロンプトが参照した場合にトリガーされます。象徴的なアニメキャラクター、ビデオゲームの主人公、コミックのスーパーヒーローなどが対象です。このカテゴリでは、blockReason: OTHER よりも finishReason: OTHER が表示される可能性が高くなります。著作権の検出は、プロンプトテキストに明示的に名前が含まれていなくても、生成された画像が保護対象のキャラクターに似始めた画像合成中に発生することが多いためです。
公人と有名人は2026年3月に大幅に厳格化されました。以前は、非論争的な文脈で公人を参照するプロンプト(例:「[有名人]に似た人がスピーチをしている」)が通過することがありました。2026年3月のポリシー更新により、より間接的な参照や芸術的スタイルの模倣も検出されるように拡張されました。以前は認識可能な公人の画像を生成できていたプロンプトがblockReason OTHERを返すようになった場合、このポリシー変更が最も可能性の高い説明です。
未成年者保護はゼロトレランスの最も厳格なカテゴリです。未成年者を不適切または搾取的な文脈で描く可能性のあるプロンプトは、即座にブロックされます。GitHub Issue #276で確認されている通り、これは法的要件であり、Googleは回避策を一切提供しないと明言しています。このフィルターは誤検出率が最も高く、子供向けイラストや家族写真に関する無害なプロンプトまでキャッチしてしまうことがあります。
ウォーターマーク除去は、参照画像のウォーターマークを除去、置換、または隠蔽するよう求めるプロンプトを対象としています。これは具体的に、参照画像が提供されブランディングや著作権表示を除去するよう指示する画像編集ワークフローに適用されます。
金融情報の改変は、2026年3月のポリシー更新で追加されたカテゴリです。金融書類、通貨、小切手、銀行取引明細書、または公的身分証明書の生成や改変を要求するプロンプトは、blockReason OTHERをトリガーするようになりました。以前は低い優先度で処理されており、レイヤー2をすり抜けることが多くありました。
衣服と顔のスワップは2026年3月に適用が強化されました。画像間で顔をスワップする、人物の肖像を別の体に配置する、誤解を招くような画像を作成し得る方法で人物の服装を変更するといったプロンプトが、より積極的にキャッチされるようになりました。このカテゴリは、対象が認識可能な人物である場合、公人カテゴリと重複します。
暗示的な性的コンテンツは最もニュアンスのあるカテゴリであり、予測が最も困難です。明示的に不適切なコンテンツを要求しないものの、コード化された言語、婉曲表現、またはモデルが暗示的と解釈する文脈的な組み合わせを使用するプロンプトをキャッチします。このカテゴリは2026年3月に拡張され、より間接的な表現パターンもキャッチするようになったため、以前は問題のなかったプロンプトがブロックをトリガーする可能性があります。
実用的なポイントとして、レイヤー2はキーワードレベルの分析ではなく、コンテンツレベルの分析で動作しています。特定の単語を避けるだけでは不十分で、モデルはプロンプト全体の意味的な意味と想定される視覚出力を評価します。以下のソリューションセクションでは、意図する創造的な出力を達成しつつコンテンツフィルタリングを回避するための具体的な戦略を紹介します。
blockReason OTHERへの5つの実証済み解決策
blockReason OTHERはセーフティ設定では解決できないため、以下の解決策は異なるアプローチを採用しています。入力の変更、ワークフローの再構築、または代替モデルへのルーティングです。これらの解決策は最もシンプルなものから最も堅牢なものへと順に並べており、プロダクション環境では複数の解決策を階層的なフォールバック戦略として実装することをお勧めします。
解決策1:トリガーパターンを除去するプロンプトの言い換え。 最も直接的なアプローチは、ブロックをトリガーした特定の言語パターンを特定して除去することです。レイヤー2はキーワードだけでなく意味的な意味を分析するため、効果的な言い換えは単純な単語の置き換えを超える必要があります。キャラクター名を一般的な説明に置き換え(特定のキャラクター名の代わりに「フレンドリーな漫画の動物」)、有名人の参照を属性の説明に置き換え(名前を出す代わりに「ショートカットの黒髪のプロフェッショナルな女性がプレゼンテーションをしている」)、複合的な概念をより単純な個別のプロンプトに分割します。複雑なシーンの説明がブロックをトリガーする場合は、個別の要素を別々に生成してから合成することを試してください。
解決策2:著作権および有名人に関する参照をすべて除去する。 これは解決策1をより積極的にしたバージョンで、blockReason OTHERエラーの原因として最も多い2つのカテゴリを具体的にターゲットにします。ブランドキャラクター、商標のビジュアルスタイル、特定のアーティストに密接に関連する認識可能な芸術スタイル、有名人の名前や公人を特定できる説明、あらゆるブランドロゴや製品デザインへの参照がないかプロンプトを監査してください。「[有名アーティスト]のスタイルで」のような間接的な参照でも、そのスタイルが著作権のある作品と密接に関連している場合はブロックをトリガーする可能性があります。
解決策3:複雑なプロンプトをシンプルな部分に分割する。 複数の概念を組み合わせた複雑なプロンプトは、各概念が追加されるごとに、組み合わされた意味的な意味がポリシー境界を超える可能性が高まるため、レイヤー2をトリガーする確率が高くなります。単一の複雑なプロンプトを2〜3のシンプルな生成リクエストに分割し、結果を合成することで、組み合わせたプロンプトでは失敗したケースでも成功することがよくあります。たとえば、「特定の服装を着た人が特定のランドマークで特定のアクションをしている」の代わりに、シーンと被写体を別々に生成します。
解決策4:タイムアウトと自動モデルフォールバックを追加する。 プロダクションアプリケーションでは、Nano Banana 2がblockReason OTHERを返した場合に代替画像モデルへ自動的にフォールバックする実装が最も信頼性の高いアプローチです。一部のプロンプトはレイヤー2によって常にブロックされるという現実を受け入れ、アプリケーションの機能を維持します。laozhang.aiのようなAPIプロキシサービスは、統一エンドポイントの背後に複数の画像モデルを集約しているため、複数のAPI統合を管理することなく、Nano Banana 2と代替モデル間のフォールバックを簡単に実装できます。
pythonimport asyncio from google import genai async def generate_with_fallback(prompt, timeout_seconds=30): """Generate image with Nano Banana 2, falling back to alternatives.""" client = genai.Client(api_key="YOUR_GEMINI_KEY") try: # Attempt Nano Banana 2 with timeout response = await asyncio.wait_for( asyncio.to_thread( client.models.generate_content, model="gemini-3.1-flash-image-preview", contents=prompt, config=types.GenerateContentConfig( response_modalities=["IMAGE", "TEXT"], ) ), timeout=timeout_seconds ) # Check for blockReason OTHER if hasattr(response, 'prompt_feedback') and response.prompt_feedback: if getattr(response.prompt_feedback, 'block_reason', None) == 'OTHER': print("Layer 2 block detected, falling back...") return await fallback_generate(prompt) # Check for empty candidates (SDK hang prevention) if not response.candidates or len(response.candidates) == 0: print("Empty candidates, falling back...") return await fallback_generate(prompt) return response except asyncio.TimeoutError: print(f"Timeout after {timeout_seconds}s, falling back...") return await fallback_generate(prompt) async def fallback_generate(prompt): """Fallback to alternative image model.""" # Example: Use GPT Image or FLUX.2 via alternative API # Implementation depends on your fallback model choice pass
解決策5:GPT ImageまたはFLUX.2をプライマリフォールバックとして使用する。 コンテンツ要件が本質的にGoogleのレイヤー2ポリシーと矛盾する場合(たとえば、ニュースや論説目的で認識可能な公人の画像を生成する必要がある場合)、唯一の信頼できる解決策は、異なるコンテンツポリシーを持つ別の画像生成モデルを使用することです。OpenAIのGPT Image(DALL-E 4o)はNano Banana 2とは異なるポリシー境界を持ち、Nano Banana 2が拒否するプロンプトを受け入れる場合があり、その逆もあり得ます。さまざまなプロバイダーを通じて利用可能なFLUX.2モデルは、さらに別のコンテンツポリシーセットを提供しています。プロダクション環境では、2〜3の異なる画像生成APIへのアクセスを維持することで、プロバイダー間のポリシーの違いがボトルネックではなくセーフティネットとして機能するようになります。
プロダクション対応のエラーハンドリング
開発時のデバッグからプロダクションの信頼性へ移行するには、これまで議論したすべての障害モードを考慮した包括的なエラーハンドリングが必要です。以下の実装は、python-genai SDKのハングバグを防止し、レイヤー1とレイヤー2のブロックを正しく区別し、自動リトライとフォールバックを実装し、モニタリング用の構造化ログを提供する、Nano Banana 2の完全なエラーハンドリングラッパーです。
pythonimport time import logging from dataclasses import dataclass from enum import Enum from typing import Optional logger = logging.getLogger(__name__) class BlockType(Enum): NONE = "none" LAYER_1_SAFETY = "layer_1_safety" LAYER_2_OTHER = "layer_2_other" LAYER_2_IMAGE_SAFETY = "layer_2_image_safety" LAYER_2_COPYRIGHT = "layer_2_copyright" LAYER_2_PROHIBITED = "layer_2_prohibited" SDK_HANG = "sdk_hang" UNKNOWN = "unknown" @dataclass class GenerationResult: success: bool block_type: BlockType image_data: Optional[bytes] = None error_message: str = "" latency_ms: int = 0 model_used: str = "" def safe_generate_image(client, prompt: str, model: str = "gemini-3.1-flash-image-preview") -> GenerationResult: """Production-safe image generation with comprehensive error handling.""" start_time = time.time() try: response = client.models.generate_content( model=model, contents=prompt, config=types.GenerateContentConfig( response_modalities=["IMAGE", "TEXT"], safety_settings=[ types.SafetySetting(category=cat, threshold="BLOCK_NONE") for cat in [ "HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_HATE_SPEECH", "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT", ] ], ), ) latency = int((time.time() - start_time) * 1000) # Check 1: Prompt-level blocking (blockReason) if hasattr(response, 'prompt_feedback') and response.prompt_feedback: block_reason = getattr(response.prompt_feedback, 'block_reason', None) if block_reason == 'SAFETY': logger.warning(f"Layer 1 block: {prompt[:80]}...") return GenerationResult( success=False, block_type=BlockType.LAYER_1_SAFETY, error_message="Layer 1 safety filter triggered. Adjust safety_settings.", latency_ms=latency, model_used=model, ) if block_reason == 'OTHER': logger.warning(f"Layer 2 block: {prompt[:80]}...") return GenerationResult( success=False, block_type=BlockType.LAYER_2_OTHER, error_message="Layer 2 policy block. Cannot bypass via settings.", latency_ms=latency, model_used=model, ) # Check 2: Empty candidates (prevents SDK hang) if not response.candidates or len(response.candidates) == 0: logger.warning(f"Empty candidates for: {prompt[:80]}...") return GenerationResult( success=False, block_type=BlockType.SDK_HANG, error_message="Empty candidates array. Likely silent Layer 2 block.", latency_ms=latency, model_used=model, ) # Check 3: Generation-level blocking (finishReason) candidate = response.candidates[0] finish_reason = getattr(candidate, 'finish_reason', 'STOP') finish_reason_map = { 'SAFETY': BlockType.LAYER_1_SAFETY, 'IMAGE_SAFETY': BlockType.LAYER_2_IMAGE_SAFETY, 'OTHER': BlockType.LAYER_2_COPYRIGHT, 'PROHIBITED_CONTENT': BlockType.LAYER_2_PROHIBITED, } if finish_reason in finish_reason_map: return GenerationResult( success=False, block_type=finish_reason_map[finish_reason], error_message=f"Generation blocked: finishReason={finish_reason}", latency_ms=latency, model_used=model, ) # Check 4: Extract image data for part in candidate.content.parts: if hasattr(part, 'inline_data') and part.inline_data: return GenerationResult( success=True, block_type=BlockType.NONE, image_data=part.inline_data.data, latency_ms=latency, model_used=model, ) # No image found in response return GenerationResult( success=False, block_type=BlockType.UNKNOWN, error_message="Response contained no image data.", latency_ms=latency, model_used=model, ) except Exception as e: latency = int((time.time() - start_time) * 1000) logger.error(f"Exception during generation: {e}") return GenerationResult( success=False, block_type=BlockType.UNKNOWN, error_message=str(e), latency_ms=latency, model_used=model, )
この実装における防御的プログラミングパターンの主要なポイントを説明します。まず、response.candidates へのすべてのアクセスはlengthチェックで保護されており、多くの開発者を不意打ちにしたpython-genai SDKのハングバグを防止しています。次に、関数は例外を発生させる代わりに構造化された結果オブジェクトを返すため、非同期パイプラインやリトライロジックでの使用が安全です。3つ目に、ブロックタイプの分類により、モニタリングシステムがどの種類のブロックがどの頻度で発生しているかを正確に追跡でき、プロンプトを長期的に最適化するために必要なデータが得られます。
プロダクションデプロイメントでは、laozhang.aiのようなプラットフォームが複数の画像生成モデルにまたがる統一APIエンドポイントを提供しており、解決策4で説明したフォールバック戦略の実装を簡素化できます。各フォールバックモデルごとに別々のAPIクライアントを管理する代わりに、単一のエンドポイントを通じてルーティングし、プラットフォームにモデルの選択とエラー回復を任せることができます。
この実装のログは、モニタリングダッシュボードをサポートするように意図的に構造化されています。すべてのリクエストの block_type、latency_ms、model_used を追跡することで、レイヤー2ブロックの異常なスパイクに対するアラートの構築(ポリシー変更を示している可能性があります)、プロンプト言い換えの効果の追跡、代替モデルにルーティングすべきプロンプトの特定が可能になります。
よくある質問
Nano Banana 2のセーフティフィルターを完全に無効にできますか?
レイヤー1のセーフティフィルターは、4つの有害カテゴリ(HARM_CATEGORY_HARASSMENT、HARM_CATEGORY_HATE_SPEECH、HARM_CATEGORY_SEXUALLY_EXPLICIT、HARM_CATEGORY_DANGEROUS_CONTENT)をすべて BLOCK_NONE または OFF に設定することで無効にできます。しかし、レイヤー2のポリシー適用は、APIパラメータ、SDK設定、アカウント設定のいずれによっても無効にすることはできません。つまり、設定可能なセーフティ設定をすべて解除しても、Googleの利用規約、著作権法、児童の安全要件に違反するコンテンツは引き続きブロックされます。レイヤー1は潜在的に有害なAI出力からユーザーを保護し、レイヤー2は法的責任からGoogleを保護するという違いがあります。両方とも必要ですが、設定可能なのは最初のレイヤーのみです。
BLOCK_NONEとOFFの違いは何ですか?
どちらの設定もレイヤー1での自動ブロックを防止しますが、メタデータの動作が異なります。BLOCK_NONE はブロックを無効にしつつ、レスポンスにセーフティレーティングを返し続けるため、どのカテゴリがどの信頼度レベルで検出されたかがわかります。これはモニタリングや監査に有用です。OFF はブロックとメタデータ収集の両方を完全に無効にし、レスポンスにセーフティ情報が一切含まれなくなります。gemini-2.5-flash以降のモデル(2026年1月時点のVertex AIドキュメントに基づく)では、OFF がデフォルト設定です。実用的な推奨事項として、開発中は BLOCK_NONE を使用し(セーフティレーティングの確認が可能)、プロダクション環境でセーフティメタデータが不要な場合は OFF を使用します(レスポンスがわずかに高速になります)。
以前動作していたプロンプトがブロックされるようになったのはなぜですか?
2026年1月や2月に動作していたプロンプトがblockReason OTHERを返すようになった場合、最も可能性の高い説明はGoogleの2026年3月のポリシー更新です。この更新では、4つの具体的なカテゴリの適用が厳格化されました:公人と有名人(間接的な参照のより広範な検出)、金融情報の改変(以前は低い優先度)、衣服と顔のスワップ(より積極的な検出)、暗示的な性的コンテンツ(拡張されたパターン認識)。プロンプトがこれらの領域に触れている場合、以前はトリガーされなかったブロックがトリガーされる可能性があります。修正方法は、影響を受けるプロンプトを監査して言い換え、特に認識可能な個人や金融書類への間接的な参照を除去することです。
無料枠のAPIでNano Banana 2の画像生成は利用できますか?
Google AI Studioの無料枠ではテキスト生成用のGeminiモデルへのアクセスが提供されますが、APIを通じた画像生成には有料プランが必要です。無料枠でもGoogle AI Studioのウェブインターフェースで画像生成を試すことはできますが、Nano Banana 2(gemini-3.1-flash-image-preview)を使用したプログラム的なAPIアクセスでの画像生成には、Google Cloudプロジェクトで課金を有効にする必要があります。これはblockReason OTHERの問題とは別であり、無料枠と有料枠の両方で発生する可能性があります。ただし、無料枠のユーザーは、画像生成リクエストがクォータレベルで最初に拒否されるため、blockReason OTHERが表示されるところまで到達しない場合があります。
blockReason OTHERが地域制限によるものかどうかをどのように判断できますか?
EU圏の開発者は、特定の法域でより厳格なコンテンツフィルターを適用するIPベースのポリシー適用により、blockReason OTHERに遭遇する頻度が高くなる可能性があります。ブロックがコンテンツベースではなく地域ベースかどうかを判断するには、まったく同じプロンプトを別の地理的地域からテストしてください(VPNや別の地域にデプロイされたクラウド関数を使用)。プロンプトが別の地域からは成功するが自分の地域からは失敗する場合、そのブロックは地域的なものです。この場合、より緩やかなポリシーの地域(米国ベースのクラウドインフラストラクチャなど)のサーバーからAPI呼び出しをデプロイすることは、その地域の該当する利用規約に準拠している限り、正当な回避策となります。
