取り組みの背景
Gemini の画像生成機能は強力ですが、複数の落とし穴があります。特に 2025 年 12 月の無料ティア IPM 制限変更により、429 RESOURCE_EXHAUSTED エラーが急増しています。
このガイドでは、画像生成 API で遭遇しやすい 5 つの主要エラーと、確実に解決するための実装パターンを紹介します。
1. 429 RESOURCE_EXHAUSTED エラー — クォータ管理の実装
問題:なぜ 429 が頻発するのか
- 無料ティア: 2025 年 12 月、Image-based RPM (IPM) が 0 に制限されました(実質的に画像生成が利用不可)
- Tier 1 アップグレード: 月 $5 支払いで IPM が上昇するはずですが、ゴーストバグで 429 が返るケースが報告されています
- 有料ティア: 正常な場合でも、バースト制限とスムージング制限の 2 段階があります
解決方法:クォータ情報を取得し、リトライロジックを実装
import google.generativeai as genai
from google.generativeai.types import generation_types
import time
genai.configure(api_key="YOUR_API_KEY")
def get_quota_info():
"""APIの現在のクォータ情報を取得"""
try:
# Quota API で残りリソースを確認
# 注: 日本の API では直接 quota エンドポイントがない場合、
# リトライ戦略で対応
return {"status": "check_needed"}
except Exception as e:
print(f"Quota info error: {e}")
return None
def generate_image_with_retry(prompt, max_retries=3):
"""指数バックオフを用いたリトライロジック"""
model = genai.GenerativeModel("gemini-2.0-flash-exp")
for attempt in range(max_retries):
try:
# 画像生成リクエスト
response = model.generate_images(
prompt=prompt,
number_of_images=1,
safety_filter_level="block_none" # 初回は安全フィルター設定を確認
)
return response
except genai.types.BlockedPromptException as e:
# 安全フィルター により ブロック
print(f"Content policy violation: {e}")
return None
except genai.types.RequestLimitExceeded as e:
# 429 エラー
if attempt < max_retries - 1:
wait_time = 2 ** attempt + 1 # 1秒、3秒、7秒...
print(f"Rate limited (429). Retrying in {wait_time}s...")
time.sleep(wait_time)
else:
print("Max retries exceeded. Upgrade to paid tier or wait.")
return None
except Exception as e:
print(f"Unexpected error: {type(e).__name__}: {e}")
return None
return None
# 使用例
result = generate_image_with_retry("A serene mountain landscape at sunset")
if result:
print(f"Image URL: {result.candidates[0].image.uri}")期待される出力:
Image URL: https://lh3.googleusercontent.com/...
クォータ超過時の回避策
- バッチ処理を分割 — 1 時間あたり最大リクエスト数を超えないよう調整
- キャッシュの活用 — 同じプロンプトに対しては、生成結果をローカルキャッシュ
- 優先順位キュー — 重要な画像から順に生成
2. 「Image generation failed」— 安全フィルターとコンテンツポリシー
問題:正当なプロンプトがブロックされる
Gemini の画像生成は Google の安全フィルターを使用しており、誤検知が発生することが知られています。
- 医学テキストを含む画像(医師の指示図解など)
- 歴史的な戦争シーン
- 実在しない人物(AI 生成キャラクター)でも「実在の人物のように見える」と判定される
解決策:プロンプトの言い換えと安全設定の調整
def generate_with_safety_options(
prompt,
safety_level="default" # "none", "default", "strict"
):
"""複数の安全レベルでトライ"""
model = genai.GenerativeModel("gemini-2.0-flash-exp")
safety_configs = {
"none": generation_types.SafetyFilterLevel.BLOCK_NONE,
"default": generation_types.SafetyFilterLevel.BLOCK_SOME,
"strict": generation_types.SafetyFilterLevel.BLOCK_MOST
}
try:
response = model.generate_images(
prompt=prompt,
number_of_images=1,
safety_filter_level=safety_configs.get(safety_level, "default")
)
return response, "success"
except genai.types.BlockedPromptException:
return None, "blocked"
# 正当なプロンプトを言い換える例
original = "医師が患者の X 線画像を説明している"
rephrased = "Medical professional reviewing radiography images in clinical setting"
result, status = generate_with_safety_options(rephrased, safety_level="default")
if status == "blocked":
print("If legitimate, consider:")
print("1. Use English prompts (sometimes less filtered)")
print("2. Use abstract/illustrated style")
print("3. Add context: 'Educational medical illustration for textbook'")よくある言い換えテクニック:
- 「人物」→ 「キャラクター」「イラスト」
- 「暴力」→ 「アクション映画のポスター風」
- 「著名人」→ 「その人風のスタイル」
3. 出力画像の破損とフォーマットエラー
問題:base64 デコード失敗と MIME タイプの不一致
Gemini は複数の画像フォーマットで返すことができますが、デコード時にエラーが起こることがあります。
import base64
import io
from PIL import Image
def save_generated_image_safely(response, output_path):
"""破損対策を含めた画像保存"""
try:
if hasattr(response.candidates[0], 'image'):
# URI形式の場合
image_data = response.candidates[0].image
if hasattr(image_data, 'uri'):
print(f"Image URL: {image_data.uri}")
# ウェブサービスの場合は直接 URL を使用
return image_data.uri
# Base64形式の場合
if hasattr(image_data, 'data'):
try:
image_bytes = base64.b64decode(image_data.data)
img = Image.open(io.BytesIO(image_bytes))
img.verify() # 破損チェック
img.save(output_path)
print(f"Saved to {output_path}")
return output_path
except Exception as decode_error:
print(f"Decode error: {decode_error}")
return None
except AttributeError as e:
print(f"Unexpected response format: {e}")
return None
# 使用例
model = genai.GenerativeModel("gemini-2.0-flash-exp")
response = model.generate_images(
prompt="A cat wearing a space suit",
number_of_images=1
)
save_generated_image_safely(response, "output.png")期待される出力:
Image URL: https://lh3.googleusercontent.com/...
# または
Saved to output.png
4. 「Model not found」エラー
問題:正しくないモデル名の指定
Gemini で画像生成に対応したモデルの名前は限定的です。
- ❌
gemini-pro-vision - ❌
gemini-2.5-pro - ✅
gemini-2.0-flash-exp(画像生成対応)
現在の正しいモデル名
# ✅ 画像生成対応のモデル
IMAGE_GENERATION_MODEL = "gemini-2.0-flash-exp"
IMAGEN_MODEL = "imagen-3" # 別ブランドの Imagen API
def list_available_models():
"""利用可能なモデルを一覧表示"""
models = genai.list_models()
for model in models:
if 'generateImage' in str(model.supported_generation_methods):
print(f"✓ Image generation: {model.name}")
else:
print(f"- Text only: {model.name}")
list_available_models()期待される出力:
✓ Image generation: models/gemini-2.0-flash-exp
- Text only: models/gemini-2.5-pro
- Text only: models/gemini-2.5-flash
5. タイムアウトと生成時間の長期化
問題:大きな画像やバッチ生成で遅延
- 画像解像度 が高い(1024x1024 以上)
- バッチ生成 — 一度に複数の異なるプロンプト
- ストリーミング を使用している場合
タイムアウト対策
import threading
def generate_with_timeout(prompt, timeout_seconds=60):
"""タイムアウト付きの画像生成"""
model = genai.GenerativeModel("gemini-2.0-flash-exp")
result = [None]
exception = [None]
def generate():
try:
result[0] = model.generate_images(
prompt=prompt,
number_of_images=1
)
except Exception as e:
exception[0] = e
thread = threading.Thread(target=generate)
thread.daemon = True
thread.start()
thread.join(timeout=timeout_seconds)
if thread.is_alive():
print(f"Timeout after {timeout_seconds}s. Try:")
print("1. Reduce image size")
print("2. Simplify prompt")
print("3. Use streaming instead")
return None
if exception[0]:
raise exception[0]
return result[0]
# 使用例
image = generate_with_timeout(
"Complex 3D scene with many details",
timeout_seconds=90
)期待される出力:
# 成功時:
Image URL: https://lh3.googleusercontent.com/...
# タイムアウト時:
Timeout after 90s. Try:
1. Reduce image size
2. Simplify prompt
3. Use streaming instead
トラブル回避のベストプラクティス
- 必ずリトライロジックを実装 — 429 は一時的なことが多い
- プロンプトをテキストで記録 — どのプロンプトがブロックされたか追跡
- 有料ティアでの十分なテスト — 無料ティアでは信頼性が低い
- 複数モデルの併用 — Imagen API も検討(別契約が必要)
詳細は Gemini API エラーハンドリング完全ガイドと API 認証エラーの FAQ を参照してください。
参考資料
- Google AI Studio 公式ドキュメント
- レート制限とクォータ管理