「compiled grammar is too large」エラーの原因とスキーマ分割で対処する方法
structured outputsで複雑なJSON Schemaを使うと出る400エラーの原因を、nullable型・$refの非重複展開・深いネストの3点から解説します。
structured outputsのoutput_config.formatで中程度に複雑なJSON Schemaを送ると、400エラーが返ることがあります。エラー文は「The compiled grammar is too large, which would cause performance issues」というものです。原因はJSON outputsのスキーマ単体にあるにもかかわらず、メッセージはstrict: trueのツール向けの「tool schemas」「strict tools」という語彙で説明されるため、混乱を招きます。原因はnullable型の分岐・$refの非重複展開・深いネストの3つに集約できます。2026年8月にAnthropicが複雑さの上限を明文化してからは、より説明的なエラーメッセージに置き換わっています。
「compiled grammar is too large」とはどんなエラーか
このエラーは、anthropic-sdk-pythonリポジトリのIssue #1185で報告されました。報告者はTypeScript SDKでoutput_config.format(JSON outputs)を使っています。5階層のネストとnullable型を含む、約50プロパティのスキーマを送信したところ、次のエラーを受け取りました。エラー発生時に使っていたモデルはclaude-sonnet-4-5とclaude-opus-4-5です。2つのモデルで同じエラーが出ており、モデル固有の問題ではないと考えられます。
400 {"type":"error","error":{"type":"invalid_request_error","message":"The compiled grammar is too large, which would cause performance issues. Simplify your tool schemas or reduce the number of strict tools.","request_id":"req_..."}}Issueの本文はエラーメッセージの語彙についても指摘しています。原因はJSON outputsのスキーマそのものにあるにもかかわらず、メッセージは「tool schemas」「strict tools」というStrict tool use側の語彙で説明されている、という点です。structured outputsの基本的な使い方では、JSON outputsとStrict tool useを別機能として扱います。ただしこのエラーは、両者に共通するグラマー(制約付きデコーディングの内部表現)のコンパイル処理から発生します。コメント欄には、Go SDKでも同じエラーに遭遇したという報告があり、特定の言語SDKに限った問題ではなさそうです。
なぜ複雑なスキーマでグラマーが肥大化するか
Issueの根本原因分析と、複数のユーザーが独立に確認した内容を突き合わせると、肥大化の要因は次の3つです。
- nullable型が分岐を生む:
{"type": ["number", "null"]}のような型配列は、内部でanyOfの分岐として展開されます。1つのオブジェクトにnullableなフィールドが増えるほど、分岐の組み合わせが掛け算的に増えます $ref・$defsはグラマーサイズを減らさない: JSON Schemaの機能一覧では$ref・$def・definitionsは対応済みの機能として扱われます。ただし複数のユーザーが確認した通り、コンパイラは参照先をインライン展開してからグラマーを組み立てるため、$refでスキーマの重複を避けても、コンパイル後のグラマーサイズは減りません。同じサブスキーマを4回参照するオブジェクトは、4回分がそのままグラマーに反映されます- 深いネストと配列項目の組み合わせ: オブジェクトの中に配列があり、その配列項目がさらにオブジェクトを持つという構造が4〜5階層続くと、各階層のプロパティ数が掛け合わされて複雑さが積み上がります
このうち1番目の「nullable型による分岐」は、公式ドキュメントのSchema complexity limitsにも記載があります。「union型を使うパラメータは指数関数的なコンパイルコストを生むため特に高コスト」という説明で、コミュニティの報告と一致します。一方で2番目の「$refが重複を減らさない」という点は、Issueの時点でAnthropicから明確な反証も修正の言及もありません。公式ドキュメントにも明示的な記載がない状態です。
効果があった回避策 — スキーマを分割する
Issueのコメント欄では、実務での回避策が次の3パターンに収束しています。
- 2段階リクエストに分割する: 1回目のリクエストで「配列の件数」「トップレベルの必須フィールド」など骨格だけを取得し、2回目以降のリクエストで骨格の各要素の詳細を埋める。1回あたりのスキーマが小さくなるため、グラマーの上限に触れにくくなる
- optionalをrequiredへ寄せる: 省略可能なフィールドはnullable型やanyOfの分岐を増やす原因になる。デフォルト値がある場合はrequiredにして、Claude自身にデフォルト値を返させる
- enumの項目数を絞る: 選択肢が多いenumはグラマーの分岐を増やす。件数が多い場合は文字列 + description(説明文)での指定に切り替える
公式ドキュメントのTipsでも、strict: trueは本当に必要なツールだけに絞ることと、ネストを浅く平坦化することが対処として挙げられています。コミュニティの回避策と合わせて、送信前に見直す価値があります。
ある投稿者は経験則として、スキーマのJSON文字列サイズが10KB程度に収まると安定してコンパイルが通ることが多いと共有しています。ただしこれは公式が保証する数値ではなく、あくまで実務上の目安です。スキーマの構造(ネスト・nullable数・enum数)によって同じサイズでも結果が変わるため、正確な判定にはなりません。
Anthropicの対応 — エラーメッセージと制限値の明文化
このIssueは2026年8月6日にAnthropic側の返信でクローズされました。返信では2点が述べられています。複雑さの上限を公式ドキュメントに明文化したこと、そして上限を超えたリクエストは「Schema is too complex for compilation」という説明的な400エラーを返すようになったことです。
明文化された上限は、1リクエストあたりstrictなツール20個まで、required外の任意プロパティが全スキーマ合計24個まで、anyOfや型配列を使うパラメータが16個まで、というものです。ただしこの20/24/16を守っていれば必ず通るわけではありません。公式ドキュメントにはコンパイル自体に180秒のタイムアウトがあると明記されており、グラマーが大きすぎればこの内部制限に触れて「Schema is too complex for compilation」の400エラーになります。この数値と回避手順はJSON Schema制限のSDK変換とStrict tool useの保証内容にまとめています。この記事で扱う「compiled grammar is too large」は、上限が文書化される前に返っていた、中身の見えないエラーメッセージでした。
ここで注意したいのは、Anthropicの返信が明言している範囲です。明言しているのは「エラーメッセージを説明的にした」ことと「上限を数値として文書化した」ことの2点だけです。Issueの本体である「$refのグラマー非重複展開を修正した」とは述べていません。スキーマを分割する回避策そのものは、返信後も引き続き有効な対処法として残ります。
ドキュメント整備だけで終わった問題か
今回の対応は、コンパイラの内部動作を変える修正ではなく、既存の挙動を文書化してエラーメッセージを分かりやすくする対応でした。これは実用上は大きな前進です。Issueの機能要望では、上限の実際の値(プロパティ数・ネスト深さ・分岐係数)についてドキュメントに案内がないことが指摘されていました。今は数値の上限表と「Schema is too complex for compilation」という具体的なメッセージがあります。少なくとも「どこを削ればよいか」の当たりはつけられます。
ただし、$refによるスキーマの重複排除がグラマーサイズに反映されないという構造そのものは変わっていません。共通のサブスキーマを複数箇所で参照する設計は、JSON Schemaの設計としては自然な選択です。それがそのままグラマー肥大化に直結する以上、スキーマの保守性とコンパイルの安定性はトレードオフの関係にあります。Python SDKでPydanticモデルを使う場合も、モデルを再利用する設計ほどこの上限に近づきやすい点は変わりません。
まとめ
「compiled grammar is too large」は、nullable型の分岐・$refの非重複展開・深いネストが重なり、複雑さの上限に達したJSON Schemaへ返っていた400エラーです。2026年8月の対応以降は「Schema is too complex for compilation」という具体的なメッセージに置き換わっています。上限もstrictツール20個・任意プロパティ24個・union型パラメータ16個という数値で明文化されました。回避策は、スキーマを2段階のリクエストに分割する・optionalをrequiredへ寄せる・enumの件数を絞るの3つです。いずれもIssueの時点から現在まで有効です。$refでスキーマを整理してもグラマーサイズは減らないため、共通サブスキーマを多用する設計では早めに分割を検討する価値があります。