PythonでGemini APIのStructured Output(構造化出力)を実装中、Pydanticモデルで階層構造を定義したところ、400エラーでハマったので備忘録として残します。
この記事でわかること
- Gemini APIで「400 Schema is invalid」が出る原因
- Pydanticにおける再帰構造の制限
- 階層構造データを安全に生成するための代替案
[現象] 実行時にスキーマエラーが発生する
ツリー構造やファイルディレクトリのような階層データを生成しようとして、以下のように自分自身をリストで持つPydanticモデルをresponse_schemaに指定すると、APIリクエスト時にエラーが発生します。
google.api_core.exceptions.InvalidArgument:
400 Schema is invalid: recursive types are not supported.
Please remove recursion from the schema.
[環境]
- Language: Python 3.10+
- Library: google-generativeai
- Validation: Pydantic v2
[原因] Gemini APIのスキーマ制限
2026年現在の仕様において、Gemini APIのresponse_schema機能は自己参照(再帰的な構造)を持つJSONスキーマをサポートしていません。
Pydanticで children: list['Node'] と定義すると、生成されるJSON Schemaに $ref を用いた再帰が含まれます。Gemini APIはこの参照解決に対応していないため、「スキーマが無効です」としてリクエストが拒絶されます。
[解決策] dict型での定義と事後バリデーション
解決策は、APIに渡すモデルからは再帰を排除し、生成されたデータをPython側で再パースするという二段階構成にすることです。
修正前のコード(エラー)
class Node(BaseModel):
name: str
children: list["Node"] # ここでエラー
修正後のコード(正常動作)
API送信用のモデルでは list[dict] として定義し、APIからのレスポンスを本来の再帰モデルで読み込み直します。
import google.generativeai as genai
from pydantic import BaseModel
from typing import List
# 1. APIスキーマ用のモデル(再帰を避ける)
class GeminiNode(BaseModel):
name: str
children: List[dict] # APIにはdictのリストとして認識させる
# 2. アプリケーションで使いたい本来の再帰モデル
class FinalNode(BaseModel):
name: str
children: List["FinalNode"]
# APIリクエスト
model = genai.GenerativeModel("gemini-1.5-flash")
response = model.generate_content(
"マインドマップの構造を生成して",
generation_config=genai.GenerationConfig(
response_mime_type="application/json",
response_schema=GeminiNode,
)
)
# 3. 取得したJSONを本来の型でパースして安全性を確保
import json
raw_data = json.loads(response.text)
validated_node = FinalNode.model_validate(raw_data)
print(validated_node)
[まとめ]
Gemini APIのStructured Outputで階層構造を扱う際は、以下のポイントを押さえましょう。
- 400 Schema is invalidが出たら再帰定義を疑う
- API用スキーマでは list[dict] や Any でお茶を濁す
- 生成されたデータに対し、Python側で本来の再帰Pydanticモデルを使ってバリデーションをかける
この方法なら、APIの制限を回避しつつ、アプリケーション内部では型安全なデータを扱うことが可能です!

