Claude Code --json-schemaエラーの直し方 — JSON Schema検証に落ちる原因
Claude Codeの--json-schemaフラグでJSON Schemaが弾かれる原因を、3段階のチェック順序とformatキーワードの扱いから解説します。v2.1.205での挙動変化つき。
このTipsでできること
claude -pに--json-schemaを渡すと、Error: --json-schema is not a valid JSON Schemaで終了コード1になり、プロンプトが実行されずに止まることがあります。この記事では、このエラーが出る3段階のチェック順序と、診断メッセージの読み方、formatキーワードの扱いを説明します。あわせて、同じ「スキーマが原因」に見えて別の層で起きるエラーの切り分けも扱います。
なぜ「is not a valid JSON Schema」が出るか
--json-schemaは非対話モード(claude -p)専用のフラグで、Claudeの応答を指定した構造に固定します。渡した値がJSON Schemaとして成立していないと、Claude Codeはプロンプトを実行せずに終了コード1で止まります。他のエラーとあわせて切り分けたい場合はよくあるエラー10選も参照してください。
渡した値は、次の順に3段階でチェックされます。どの段階で落ちたかは、エラーメッセージの文言で分かります。
--json-schemaの値が通る3つのチェック
- 1
JSONとしてパースできるか
失敗すると
Error: --json-schema is not valid JSONで止まります。引用符や括弧の閉じ忘れが典型です。 - 2
パース結果がオブジェクトか
配列や文字列だと
Error: --json-schema must be a JSON objectになります。 - 3
JSON Schemaとしてコンパイルできるか
ここで落ちると
Error: --json-schema is not a valid JSON Schemaに続けて、検証器の診断が付きます。
3番目のエラーメッセージの末尾には、具体的な診断が入ります。
Error: --json-schema is not a valid JSON Schema: data/type must be equal to one of the allowed values2つ目のコロンより後ろが検証器の診断そのもので、失敗したキーワードや位置を指します。例のdata/typeは、typeキーワードが許可された値のどれでもないことを示します。
フラグ自体の仕様はclaude --helpで見られます。v2.1.287では、--json-schemaは次のように表示されます。
--json-schema <schema> JSON Schema for structured output
validation. Example:
{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}同じヘルプで--output-formatには「only works with --print」と添えられており、-pなしでは使えない出力系フラグの仲間です。
診断メッセージが指す箇所を直す
最短ルートは、診断が指す箇所をそのまま修正することです。たとえば次のようにtypeに"str"と書くと弾かれます。
{"type":"str"}{"type":"string"}"str"はPythonの型名を流用した誤記です。JSON Schemaが許すtypeの値は"object" "array" "string" "number" "integer" "boolean" "null"の7つで、"string"に直せば通ります。
どこが悪いか見当がつかないときは、最小構成から足していきます。まず{"type":"object"}のような単純なスキーマで通ることを確かめ、propertiesやrequiredを1つずつ追加すると、どの追加で壊れたかを特定できます。動作確認には次のコマンドを使います。
claude -p "auth.pyから関数名を抽出して" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'成功すると、レスポンスのstructured_outputフィールドに{"functions": [...]}形式のJSONが入ります。resultは通常のテキスト応答、structured_outputはスキーマに沿った構造化データという役割分担です。
同じ「スキーマが原因」でも、エラーが出る層は3つある
--json-schemaまわりのエラーは、どこで起きるかで対処が変わります。CLIが起動時に出すエラーは手元のマシンで完結する検査で、API側のエラーはリクエストを送った後に返ります。
| エラーの見え方 | 起きる場所 | 直し方 |
|---|---|---|
Error: --json-schema is not a valid JSON Schema: ... | 起きる場所CLI(実行前) | 直し方診断が指すキーワードを直す |
API Error: 400 ... tools.N.custom.input_schema: JSON schema is invalid | 起きる場所API(ツール定義のスキーマ) | 直し方該当のMCPサーバーを更新・無効化する |
400でSchema is too complex for compilation | 起きる場所API(構造化出力の文法コンパイル) | 直し方省略可能なプロパティやユニオン型を減らす |
結果のsubtypeがerror_max_structured_output_retries | 起きる場所Agent SDK(出力の検証失敗) | 直し方スキーマを絞り、プロンプトを明確にする |
2行目は名前が似ていますが別物です。--json-schemaで渡したスキーマではなく、MCPサーバーなどがリクエストに載せたツールのinput_schemaが対象で、番号のNはツール一覧の位置を表します。スキーマはdraft 2020-12に合わないと弾かれます。$schemaで他の方言を宣言したスキーマは、このメタスキーマ検査の対象外ですが、トップレベルのプロパティ名の検査は受けるので、同じエラーは出ます。どのツールが原因かは、エラー文では位置の番号でしか分かりません。v2.1.216以降なら、各サーバーのログにツール名を示す行がないかを確かめます。どのログにも無ければ、サーバーを1つずつ無効化して絞り込みます。
3行目は、APIやSDKで構造化出力に同じスキーマを使う場合に、APIが構造化出力のスキーマを文法にコンパイルする段階で出ます。上限は、strictを付けたツールが1リクエストあたり20個、省略可能なパラメーターが合計24個、anyOfや型の配列を使うパラメーターが合計16個です。省略可能なパラメーターが増えるほどコンパイルの状態数が膨らむため、可能ならrequiredに入れ、ネストを平らにする順で減らします。明示された上限を満たしていても、文法の大きさの内部上限を超えると同じ400になります。コンパイルには180秒のタイムアウトもあります。
4行目はAgent SDKの結果メッセージに出ます。出力が条件を満たせないまま再試行の上限に達した場合に付き、スキーマが複雑すぎる、タスクが曖昧、再試行で直せなかった、といった原因が挙げられています。モデルのフォールバックで完成済みの出力が取り消された場合にも、同じsubtypeで終わります。どちらが原因かは、結果メッセージのerrorsリストで見分けます。
formatキーワードは検証エラーにならない
JSON Schemaのformatキーワード("format": "email"のような値の形式指定)を含むスキーマは、--json-schemaの検証を通ります。Claude Codeはformatを注釈として受け取るだけで、値の形式を強制しません。format: "email"と書いても、返ってきた値がメール形式かどうかは検査されません。
形式を守らせたいときは、スキーマの外で受け側が検証します。たとえばシェルスクリプトなら、jqで取り出した値に正規表現を当てる、といった形です。
使えるキーワードと使えないキーワード
Agent SDKのドキュメントは、基本の型、enum、const、required、ネストしたオブジェクト、$refを使えると説明し、詳細な一覧としてAPIの構造化出力のページを案内しています。そのページの一覧を要点だけ抜き出すと次のとおりです。
| 区分 | 内容 |
|---|---|
| 使える | 内容基本の型、enum(文字列・数値・真偽値・nullのみ)、const、anyOfとallOf(制限つき)、$refとdefinitions(外部$refは不可)、default |
| 使える(条件つき) | 内容requiredと、falseに限ったadditionalProperties、minItemsは0と1のみ、formatはdate-time・email・uuidなど10種 |
| 使えない | 内容再帰的なスキーマ、minimum / maximum / multipleOf、minLength / maxLength、外部$ref |
使えないキーワードを含めると、APIが400エラーで詳細を返します。数値の範囲や文字数の上限をスキーマで縛りたくなる場面では、受け取った後の処理で検査する形になります。正規表現のpatternは、使える構文が限られています。
API側のformatは10種の文字列形式に限られ、CLIの--json-schemaが注釈として受け入れる動作とは別です。
v2.1.205より前とどう変わったか
--json-schemaの検証ロジックは、v2.1.205(2026年7月8日)で変わりました。
| 挙動 | v2.1.204以前 | v2.1.205以降 |
|---|---|---|
| 不正なスキーマを渡したとき | v2.1.204以前エラーなしで、構造化されていない通常のテキストが返る | v2.1.205以降Error: --json-schema is not a valid JSON Schemaで終了コード1、プロンプトは実行されない |
formatキーワードを含むスキーマ | v2.1.204以前常に無効なスキーマとして扱われた | v2.1.205以降注釈として許可され、検証エラーにならない |
v2.1.204以前は、スキーマが壊れていてもエラーが出ず、通常のテキスト応答に切り替わっていました。CIではstructured_outputの有無を見ないと壊れたスキーマに気づけなかったことになります。v2.1.205以降は実行前に止まるので、失敗の検知は早くなりました。裏返すと、以前は素通りしていた壊れたスキーマは、更新後に初めてエラーとして表に出ます。
構造化出力まわりの修正は、v2.1.205の前にもありました。v2.1.187(2026年6月23日)では、--json-schemaでモデルが成功後もStructuredOutputを何度も呼び直し続けることがある不具合と、後続のターンで構造化出力が安定して返らない不具合が直っています。古いバージョンで出力が返らない、あるいは応答が終わらないときは、スキーマを疑う前にclaude --versionでバージョンを確かめる価値があります。
Agent SDKはdraft-07、ツール定義はdraft 2020-12
claude -pはAgent SDKをコマンドラインから使う入口にあたります。SDKの構造化出力のドキュメントでは、スキーマの検証にdraft-07を使うため、それより新しい版を宣言したスキーマは弾かれると説明されています。Zodは既定でdraft 2020-12のスキーマを出力するので、変換時にtarget: "draft-7"を指定します。
const schema = z.toJSONSchema(FeaturePlan, { target: "draft-7" });このターゲットを省くと、スキーマの内容が正しくても、検証器が解釈できずにエラーになります。Zodからスキーマを生成するときは、targetの指定が要ります。Pydanticのモデルからは.model_json_schema()で生成する方法が案内されています。
前の節で触れたMCPツール定義のエラーは、検証の物差しがdraft 2020-12です。SDKの構造化出力はdraft-07なので、層が違えば物差しも違います。
CIやスクリプトに組み込むとき
--json-schemaはCIやバッチ処理から呼ぶ場面が多いフラグです。スキーマの文法エラーはプロンプトの実行前に終了コード1で戻るため、スクリプト側では終了コードを見れば検知できます。成功時の出力は--output-format jsonと組み合わせるとstructured_outputフィールドに入り、jqで取り出せます。
result=$(claude -p "auth.pyから関数名を抽出して" \
--output-format json \
--json-schema "$(cat schema.json)") || { echo "claude failed" >&2; exit 1; }
echo "$result" | jq -e '.structured_output'jq -eは結果がnullやfalseのとき非ゼロで終わるので、structured_outputが空だった場合もスクリプトの失敗として扱えます。スキーマをファイルに切り出しておくと、バージョン管理や差分レビューがしやすくなる利点もあります。
CLIが3段階で見る内容の最初の2つは、claudeを起動する前にjqで再現できます。
jq empty schema.json # 1段階目: JSONとしてパースできるか
jq -e 'type=="object"' schema.json # 2段階目: オブジェクトかjq 1.7.1では、閉じ括弧が欠けたファイルにjq emptyを実行するとparse errorで終了コード5、配列のファイルに2つ目のコマンドを実行すると終了コード1になります。3段階目のコンパイルはjqでは見られないので、一般的なJSON Schemaバリデーターに通すか、claudeを実際に実行して診断を読みます。スキーマを複数のスクリプトで使い回すなら、この事前チェックを共通のCIジョブに切り出しておく方法もあります。
構造化出力の実装手順は構造化出力の実装ガイド、SDK側の使い方はAgent SDKの入門にあります。
まとめ
まずjqで1・2段階目を先に潰し、それでも出るなら、プロンプトが実行される前に終了コード1で止まったかどうかでCLIの文法エラーかを見分けます。バージョンが古い場合は、スキーマを疑う前にclaude --versionを確かめます。