OpenAI APIのStructured Outputsを使おうとしたところ、Invalid schemaやJSON Schema関連のエラーが出て、リクエスト自体が失敗することがあります。
通常のJSON Schemaとしては問題なさそうに見えても、Structured Outputsではそのまま利用できないSchemaがあります。
特に間違いやすいのが、requiredとadditionalPropertiesです。
OpenAIのStructured Outputsでは、基本的にpropertiesで定義したすべてのフィールドをrequiredへ含める必要があり、objectにはadditionalProperties: falseを指定する必要があります。また、通常のJSON Schemaで利用できる機能すべてに対応しているわけではありません。OpenAI公式ドキュメントでも、Structured Outputsが対応するのはJSON Schemaのサブセットであると説明されています。
この記事では、Structured OutputsでJSON Schemaエラーになる代表的な原因と、requiredやadditionalPropertiesを正しく設定する方法を解説します。ZodやPydanticを使った実装の全体像、拒否・未完了の処理、業務ルールの検証などはLLMのJSON出力が壊れる原因|Structured Outputs・Zodで安全に検証する方法で解説しているため、この記事ではJSON Schemaレベルでの原因切り分けに絞ります。
- Structured Outputsとは
- 最も多い原因はrequiredの指定漏れ
- 任意項目はrequiredから外すのではなくnullを使う
- additionalProperties: falseがないとエラーになる
- ネストしたobjectにもadditionalProperties: falseが必要
- array内のobjectでも同じルールが適用される
- requiredにはpropertiesの全キーを入れる
- ルートをarrayにするとエラーになる
- JSON Schemaのすべての機能が使えるわけではない
- fine-tunedモデルではSchema制約がさらに異なる
- Structured Outputs非対応モデルを使っていないか確認する
- Responses APIならtext.formatを確認する
- Chat Completionsではresponse_formatを使う
- 手書きSchemaでは最小構成から試す
- Schemaが大きすぎる場合にも制限がある
- additionalPropertiesをtrueにして柔軟なJSONを作ることはできない
- 「JSONとして正しい」と「Structured Outputsで正しい」は別
- requiredエラーが出たときの確認方法
- additionalPropertiesエラーが出たときの確認方法
- Structured OutputsのJSON Schemaエラーに関するよくある質問
- まとめ
Structured Outputsとは
Structured Outputsは、AIから返されるJSONを指定したJSON Schemaに従わせるための機能です。
単に「JSONで返してください」とプロンプトへ書く場合と違い、Structured Outputsでは、フィールド名やデータ型、enumなどをSchemaとして定義できます。
OpenAIによると、Structured Outputsではモデルのレスポンスを指定したJSON Schemaへ準拠させることができ、必須キーの欠落や存在しないenum値などを防ぎやすくなります。
たとえば次のようなレスポンスを必ず返したいとします。
{
"title": "Structured Outputsとは",
"category": "AI",
"published": true
}
この場合、Schemaを次のように定義できます。
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"category": {
"type": "string"
},
"published": {
"type": "boolean"
}
},
"required": [
"title",
"category",
"published"
],
"additionalProperties": false
}
一見すると普通のJSON Schemaですが、Structured Outputsでは特に最後のrequiredとadditionalPropertiesが重要になります。
最も多い原因はrequiredの指定漏れ
Structured OutputsでSchemaエラーが発生した場合、最初に確認したいのがrequiredです。
一般的なJSON Schemaでは、propertiesへフィールドを定義しても、必ずしもすべてをrequiredへ入れる必要はありません。
たとえば通常のJSON Schemaなら、次のようにtitleだけを必須にする設計もできます。
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title"
]
}
しかしOpenAIのStructured Outputsでは、この考え方が異なります。
公式ドキュメントでは、Structured Outputsを利用する場合、すべてのフィールドまたはFunction parameterをrequiredとして指定する必要があるとされています。
そのため、propertiesにtitleとdescriptionがあるなら、次のように両方を含めます。
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
],
"additionalProperties": false
}
propertiesには存在するのにrequiredへ入っていないフィールドがある場合、Structured OutputsではSchemaが拒否される可能性があります。
任意項目はrequiredから外すのではなくnullを使う
ここで疑問になるのが、「任意項目を作りたい場合はどうするのか」という点です。
たとえば記事データを生成するとして、descriptionが存在しないケースを許可したいとします。
通常のJSON Schemaならdescriptionをrequiredから外したくなります。
しかしStructured Outputsでは、フィールドそのものはrequiredにしたまま、型としてnullを許可します。
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": [
"string",
"null"
]
}
},
"required": [
"title",
"description"
],
"additionalProperties": false
}
このSchemaなら、値が存在するときは次のようになります。
{
"title": "Structured Outputsとは",
"description": "JSON Schemaに従った出力を生成する機能です"
}
値がない場合は次のようにできます。
{
"title": "Structured Outputsとは",
"description": null
}
OpenAI公式ドキュメントでも、すべてのフィールドをrequiredにしたうえで、任意項目を表現したい場合はnullとのunionを使う方法が案内されています。
「optionalだからrequiredから消す」のではなく、「キーは必ず存在するが、値としてnullを許可する」と考えると分かりやすいでしょう。
JavaScript/TypeScriptでZodから生成する場合も同じ制約を受けます。optional()ではなくnullable()を使う具体的な書き方はLLMのJSON出力が壊れる原因|Structured Outputs・Zodで安全に検証する方法の「OptionalではなくNullableを使う」で解説しています。
additionalProperties: falseがないとエラーになる
requiredと並んで非常に多い原因が、additionalPropertiesの指定漏れです。
次のSchemaを見てみます。
{
"type": "object",
"properties": {
"title": {
"type": "string"
}
},
"required": [
"title"
]
}
通常のJSON Schemaとして見ると、それほど不自然ではありません。
しかしStructured Outputsでは、objectに対してadditionalProperties: falseを指定する必要があります。
修正すると次のようになります。
{
"type": "object",
"properties": {
"title": {
"type": "string"
}
},
"required": [
"title"
],
"additionalProperties": false
}
additionalPropertiesは、propertiesへ定義していない追加フィールドを許可するかどうかを決める設定です。
たとえば次のSchemaを考えます。
{
"type": "object",
"properties": {
"title": {
"type": "string"
}
},
"required": [
"title"
],
"additionalProperties": false
}
この場合、想定されている出力は次のようなものです。
{
"title": "AI開発入門"
}
一方、モデルが勝手に次のようなフィールドを追加することは許可されません。
{
"title": "AI開発入門",
"author": "AI",
"score": 95
}
OpenAIはStructured Outputsについて、Schemaで指定したキーと値だけを生成するため、objectではadditionalProperties: falseを必須としていると説明しています。
ネストしたobjectにもadditionalProperties: falseが必要
特に見落としやすいのが、Schemaをネストした場合です。
ルートのobjectだけにadditionalProperties: falseを書けばよいと思ってしまうことがあります。
たとえば次のSchemaです。
{
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"category": {
"type": "string"
}
},
"required": [
"title",
"category"
]
}
},
"required": [
"article"
],
"additionalProperties": false
}
外側にはadditionalProperties: falseがありますが、articleのobjectにはありません。
Structured Outputsで利用するなら、内側のobjectにも追加します。
{
"type": "object",
"properties": {
"article": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"category": {
"type": "string"
}
},
"required": [
"title",
"category"
],
"additionalProperties": false
}
},
"required": [
"article"
],
"additionalProperties": false
}
ネストしたSchemaでエラーになる場合は、ルートだけを見るのではなく、すべてのtype: "object"を確認するのが重要です。
OpenAI公式のネストされたSchema例でも、それぞれのobjectへadditionalProperties: falseが設定されています。
array内のobjectでも同じルールが適用される
配列の中にobjectを入れる場合も同様です。
たとえば記事一覧を返すSchemaを考えます。
{
"type": "object",
"properties": {
"articles": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"title",
"url"
]
}
}
},
"required": [
"articles"
],
"additionalProperties": false
}
この場合もitems内のobjectにadditionalProperties: falseがありません。
次のように修正します。
{
"type": "object",
"properties": {
"articles": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"title",
"url"
],
"additionalProperties": false
}
}
},
"required": [
"articles"
],
"additionalProperties": false
}
Schemaが大きくなるほど、配列内部のobjectへ設定するのを忘れやすくなります。
additionalPropertiesエラーが消えない場合は、Schema全体から"type": "object"を検索すると見つけやすいでしょう。
requiredにはpropertiesの全キーを入れる
requiredを書いているのにエラーになる場合は、配列の中身も確認します。
次のSchemaではrequired自体は存在しています。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"country": {
"type": "string"
}
},
"required": [
"name",
"age"
],
"additionalProperties": false
}
しかしpropertiesにはcountryもあります。
Structured Outputsではすべてのフィールドをrequiredとして扱う必要があるため、次のように修正します。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"country": {
"type": "string"
}
},
"required": [
"name",
"age",
"country"
],
"additionalProperties": false
}
Schemaを修正するときは、requiredの有無だけでなく、
propertiesに存在するキー
と
requiredに存在するキー
が完全に一致しているか確認してください。
ルートをarrayにするとエラーになる
requiredやadditionalPropertiesを修正してもエラーが残る場合は、Schemaのルートを確認します。
Structured Outputsでは、ルートレベルはobjectである必要があります。
たとえば記事一覧だけを返したいからといって、次のようにルートをarrayにする設計は避けます。
{
"type": "array",
"items": {
"type": "string"
}
}
代わりにobjectで包みます。
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"items"
],
"additionalProperties": false
}
OpenAI公式ドキュメントでは、Structured OutputsのルートSchemaはobjectである必要があり、ルートでanyOfを利用することもできないとされています。
ZodのdiscriminatedUnion()のように内部でanyOfを生成するヘルパーをルートへ直接使った場合も同じ理由で失敗します。この場合にルートを単一objectへまとめる具体的な設計はLLMのJSON出力が壊れる原因|Structured Outputs・Zodで安全に検証する方法の「ルートをオブジェクトにする」で解説しています。anyOf自体が完全に禁止されているわけではなく、ルート以外の位置では各Schemaが対応条件を満たせば利用できます。
JSON Schemaのすべての機能が使えるわけではない
Structured Outputsで重要なのは、JSON Schemaに対応しているからといって、JSON Schemaの全機能が利用できるわけではないという点です。
OpenAI公式ドキュメントでは、Structured OutputsはJSON Schemaのサブセットに対応すると明記されています。基本的な型としてstring、number、boolean、integer、object、array、enum、anyOfなどを利用できます。
一方、現在はallOf、not、dependentRequired、dependentSchemas、if、then、elseなどには対応していません。strict: trueで未対応のJSON Schemaを送信するとエラーになると説明されています。
外部ライブラリが自動生成した巨大なJSON SchemaをそのままStructured Outputsへ渡している場合、この制限に引っかかる可能性があります。
$refを使った再帰的なSchema(親子関係を持つツリー構造など)は技術的には利用できますが、ネストが深くなるほど不安定になりやすいと報告されています。ツリー構造のデータを扱う場合は、Schemaを再帰させるより、親IDを持たせたフラットなリストへ変換して表現するほうが安全です。
fine-tunedモデルではSchema制約がさらに異なる
ファインチューニングしたモデルを利用している場合は、通常モデルとの差にも注意が必要です。
OpenAI公式ドキュメントでは、fine-tuned modelsについて、stringのminLength、maxLength、pattern、format、numberのminimumやmaximum、arrayのminItemsやmaxItemsなど、一部の制約がさらにサポートされないとされています。
そのため、
{
"type": "string",
"maxLength": 100
}
のようなSchemaが、利用するモデルによって問題になるケースもあります。
Schemaエラーがモデル変更後に発生した場合は、モデル自体がStructured Outputsへ対応しているかだけでなく、そのモデルで利用できるJSON Schema制約も確認してください。
Structured Outputs非対応モデルを使っていないか確認する
Schemaが正しくても、利用しているモデル自体がStructured Outputsへ対応していなければ利用できません。
2026年9月時点では、たとえばGPT-5.6 SolはStructured Outputsに対応しています。OpenAIのモデルページでもFunction CallingとStructured Outputsの両方がSupportedとされています。
一方、すべてのOpenAIモデルがStructured Outputsへ対応しているわけではありません。
音声専用モデルや一部の特殊モデルなどでは利用できないことがあります。
モデルを変更した直後からStructured Outputsが失敗するようになった場合は、モデルページのStructured outputs欄を確認するとよいでしょう。
Responses APIならtext.formatを確認する
OpenAI APIでは、利用しているAPIによってStructured Outputsの指定場所が異なります。
現在のResponses APIでは、text.formatとしてSchemaを指定できます。
JavaScript SDKとZodを利用する場合、たとえば次のように書けます。
import OpenAI from "openai";
import { zodTextFormat } from "openai/helpers/zod";
import { z } from "zod";
const openai = new OpenAI();
const Article = z.object({
title: z.string(),
category: z.string(),
description: z.string().nullable()
});
const response = await openai.responses.parse({
model: "gpt-5.6",
input: "AI開発についての記事情報を作成してください",
text: {
format: zodTextFormat(Article, "article")
}
});
console.log(response.output_parsed);
現在のOpenAI公式ドキュメントでも、Responses APIではresponses.parse()とtext.formatを利用する例が案内されています。
古い記事やChat Completions用のサンプルと混ぜると、JSON Schemaそのものではなくリクエスト形式の問題でエラーになることがあります。
Chat Completionsではresponse_formatを使う
Chat Completions APIを使う場合は形式が異なります。
Zodを利用する公式例では次のようにresponse_formatを指定します。
const completion = await openai.chat.completions.parse({
model: "gpt-5.6",
messages: [
{
role: "user",
content: "記事データを生成してください"
}
],
response_format: zodResponseFormat(Article, "article")
});
Responses APIではtext.format、Chat Completionsではresponse_formatという違いがあります。
JSON Schemaエラーだと思ってSchemaだけを何度も変更しても直らない場合は、使用しているエンドポイントとサンプルコードが一致しているか確認してください。
手書きSchemaでは最小構成から試す
巨大なSchemaでエラーが発生した場合、最初からすべてを確認するのは大変です。
その場合は一度Schemaを最小構成まで減らすと原因を切り分けやすくなります。
まず次の程度まで単純化します。
{
"type": "object",
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
],
"additionalProperties": false
}
これで成功するなら、モデルやAPI呼び出し自体ではなく、元のSchemaに原因がある可能性が高くなります。
その後、objectやarrayを1つずつ戻していけば、どの部分でSchemaエラーが発生するのか特定しやすくなります。
Schemaが大きすぎる場合にも制限がある
Structured OutputsにはSchemaサイズにも上限があります。
OpenAI公式ドキュメントによると、Schema全体で利用できるobject propertyは最大100個、ネストは最大5階層です。また、property名・definition名・enum値・const値を合計した文字列長は15,000文字以下、enum値の総数は500個までという上限もあります。
通常の小規模なレスポンスSchemaで問題になることは少ないですが、データベースSchemaやOpenAPI Schemaなどから巨大なJSON Schemaを自動生成している場合には注意が必要です。
「Schemaの内容は正しいはずなのに、大きくした途端にエラーになった」という場合はサイズ制限も確認してください。これらの上限値はOpenAIのアップデートによって変更される可能性があるため、最新の公式ドキュメントもあわせて確認することをおすすめします。
additionalPropertiesをtrueにして柔軟なJSONを作ることはできない
Structured Outputsを使いながら、「基本的なフィールドだけ決めて、それ以外はAIに自由に追加させたい」という設計を考える場合があります。
たとえば次のようなSchemaです。
{
"type": "object",
"properties": {
"title": {
"type": "string"
}
},
"required": [
"title"
],
"additionalProperties": true
}
Structured Outputsではこのような用途には向きません。
OpenAIは、Structured Outputsでは指定されたキーと値だけを生成するため、additionalProperties: falseを要求しています。
自由な追加データが必要なら、
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"metadata": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"key",
"value"
],
"additionalProperties": false
}
}
},
"required": [
"title",
"metadata"
],
"additionalProperties": false
}
のように、自由度が必要な部分そのものをSchemaとして表現する方法を検討できます。
「JSONとして正しい」と「Structured Outputsで正しい」は別
Structured Outputsのエラーで混乱しやすい最大の理由は、JSON、JSON Schema、Structured Outputsの制約を混同してしまうことです。
次のSchemaはJSONとしては正しい場合があります。
{
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
JSON Schemaとしても一般的には成立します。
しかしStructured Outputsでは、
{
"type": "object",
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"additionalProperties": false
}
のように、さらにStructured Outputs側の条件を満たす必要があります。
そのため、オンラインのJSON Schema Validatorで「Valid」と表示されたとしても、OpenAI APIでもそのまま利用できるとは限りません。
requiredエラーが出たときの確認方法
required関連でエラーになった場合は、Schema内の各objectを順番に確認します。
たとえば次の部分があれば、
"properties": {
"name": {},
"email": {},
"age": {}
}
対応するrequiredは、
"required": [ "name", "email", "age" ]
となっている必要があります。
ネストしたobjectがある場合は、その階層でも同じ確認を行います。
外側のrequiredが正しくても、内側で1項目だけ抜けていればSchema全体が失敗する可能性があります。
additionalPropertiesエラーが出たときの確認方法
additionalProperties関連の場合は、Schema全体から次の記述を探します。
"type": "object"
見つかったobjectそれぞれに、
"additionalProperties": false
が存在するか確認します。
特に見落としやすいのは、arrayのitems、anyOf内部、$defs内、複数階層にネストされたobjectです。
OpenAI公式の$defsを利用した例でも、定義されたobjectそれぞれにrequiredとadditionalProperties: falseが設定されています。
Structured OutputsのJSON Schemaエラーに関するよくある質問
Qrequiredにすべてのフィールドを入れると任意項目は作れませんか
A作れます。任意項目はrequiredから外すのではなく、フィールドをrequiredへ残したまま型をstringとnullのunion(例: [“string”, “null”])にします。値が存在しない場合はキー自体を省略するのではなく、値としてnullを返す設計にします。
QadditionalPropertiesはルートオブジェクトだけに書けばよいですか
Aいいえ。ネストしたobject、arrayのitems内のobject、$defs内のobjectなど、Schema内に存在するすべてのtype: objectへadditionalProperties: falseが必要です。ルートだけに設定してエラーが消えない場合は、Schema全体からtype: objectを検索して確認してください。
QStructured OutputsとZodのoptional/nullableの違いは何ですか
AStructured Outputsではすべてのフィールドがrequired扱いになるため、Zodのoptional()は制約と合わずエラーの原因になります。任意項目にはnullable()を使用します。具体的な書き方は関連記事のLLMのJSON出力が壊れる原因で解説しています。
QSchemaのサイズ制限はどのくらいですか
AOpenAI公式ドキュメントによると、Schema全体で利用できるobject propertyは最大100個、ネストは最大5階層です。property名・definition名・enum値・const値を合計した文字列長は15,000文字以下という上限もあります。外部ツールで自動生成した巨大なSchemaではこの制限に注意してください。
Qルートをarrayにできないのはなぜですか
AStructured OutputsのルートSchemaはobjectである必要があり、ルートでarrayやanyOfを使うことはできません。配列を返したい場合も、items配列をプロパティとして持つobjectで包む設計にします。
Qfine-tunedモデルでは何が変わりますか
A通常モデルより制約が増えます。stringのminLength・maxLength・pattern・format、numberのminimum・maximum、arrayのminItems・maxItemsなど、一部の制約がさらにサポートされない場合があります。モデル変更後にSchemaエラーが出た場合は、そのモデルで利用できる制約を確認してください。
QSchemaエラーの原因を効率よく調べる方法はありますか
ASchemaを最小構成(1つのstringプロパティだけなど)まで減らしてから、objectやarrayを1つずつ戻していく方法が有効です。どの段階でエラーが再発するかを確認すれば、原因となっている箇所を特定しやすくなります。
まとめ
Structured OutputsでInvalid schemaなどのエラーが発生した場合、複雑なプロンプトやモデルの挙動を調べる前にSchemaを確認するのが近道です。
特に重要なのは、propertiesで定義したフィールドがすべてrequiredへ入っていることと、すべてのobjectへadditionalProperties: falseが設定されていることです。
任意項目が必要だからといってrequiredから削除するのではなく、string | nullなどnullableな型として定義します。
それでも直らなければ、ルートがobjectになっているか、ルートにanyOfを置いていないか、Structured Outputsで未対応のJSON Schema機能を使用していないか、Schemaサイズの上限を超えていないか、モデルがStructured Outputsへ対応しているかを確認します。
Structured OutputsはJSONの形式崩れを防ぐ強力な機能ですが、通常のJSON Schemaより制約が強いため、「一般的なJSON Schemaとして正しいか」ではなく、「OpenAIのStructured Outputsが対応しているJSON Schemaか」という視点で確認することが重要です。

