fix: Always set additionalProperties=false for strict schema compliance#2743
fix: Always set additionalProperties=false for strict schema compliance#2743yashwantbezawada wants to merge 2 commits into
Conversation
Fixes openai#2740 The `to_strict_json_schema` function now always sets `additionalProperties` to `false` for object types, as required by the OpenAI API for structured output. Previously, it only set this value when the key was missing, which caused issues with Pydantic models using `extra="allow"`. When Pydantic models use `ConfigDict(extra="allow")`, the generated schema includes `"additionalProperties": true`. However, the OpenAI API requires `"additionalProperties": false` for structured output to work correctly. Changes: - Modified `_ensure_strict_json_schema()` to unconditionally set `additionalProperties = false` for all object types - Added comprehensive test case `test_pydantic_extra_allow()` to verify the fix handles models with `extra="allow"` correctly This ensures API compliance while maintaining backward compatibility with existing code.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| typ = json_schema.get("type") | ||
| if typ == "object" and "additionalProperties" not in json_schema: | ||
| if typ == "object": | ||
| # Always set additionalProperties to False for strict schema compliance. | ||
| # The OpenAI API requires additionalProperties=false for structured output, | ||
| # even if Pydantic models use extra="allow" which sets it to True. | ||
| json_schema["additionalProperties"] = False |
There was a problem hiding this comment.
Preserve schemas for typed dictionaries when enforcing strictness
Overwriting additionalProperties unconditionally means any object schema that intentionally defines a value schema for dynamic keys (e.g. Pydantic fields of type Dict[str, T]) now loses that schema and becomes additionalProperties: False. These dict fields previously produced {"additionalProperties": {…}} so the model could accept arbitrary keys whose values match the inner schema; after this change the generated schema forbids all keys, so structured outputs containing mappings can never validate even though the underlying model allows them. Consider only forcing False when the value is a boolean and leaving structured additionalProperties schemas intact.
Useful? React with 👍 / 👎.
Addresses review feedback:
- Only set additionalProperties=False when it's True (from extra="allow")
or missing, preserving structured schemas for Dict[str, T] types
- Convert test to use inline snapshots as requested
This fix ensures that Dict[str, T] typed fields maintain their structured
additionalProperties schemas (e.g., {"type": "number"}) instead of being
forced to False, which would break validation for dynamic keys.
|
should we preserve schemas in additionalProperties? is that supported by openai? |
|
Yes, preserving structured The fix only sets The original code was breaking |
Interestingly, the documentation you linked to doesn't say that, as far as I can tell. All of the examples are In the hopes of speeding along the deployment of this fix, below are some examples demonstrating @yashwantbezawada's comment to be correct. The second one could be adapted into a test case, and suggests that adding That outputs: Note the second example also succeeds on the latest published version of openai python library ( However on commit cdebce9 ( So failing to preserve schemas in additionalProperties would be a breaking change, and make the JSON vs Pydantic APIs less consistent. |
|
This PR seems like a simple fix for an unambiguous bug. My comment above gave quite precise testing instructions demonstrating that it works and that the old versions failed, in addition to the test case added in the PR. Is there anything I can do to help with getting this PR merged? This issue is making it harder for my employer (Akasa) to continue using the OpenAI API. We're currently using a fork of the client library from 3 months ago which complicates our python dependency setup and makes debugging issues with use of your APIs harder. Lower probability, but it's also a potential security/compliance issue if any critical bugs are found in in the client library. Not to put too fine a point on it, but Anthropic recently launched structured outputs on AWS bedrock, covered by the AWS BAA. This has made it feasible for us to switch to another vendor, though no decision has been made as of yet. Their client library does not have this bug, and integrating with it was quite straightforward. |
Summary
Fixes #2740
This PR resolves an issue where Pydantic models using
ConfigDict(extra="allow")fail when used with structured output becauseadditionalPropertiesis not forced tofalse.Problem
The OpenAI API requires
"additionalProperties": falsein JSON schemas for structured output (response_format). When Pydantic models useextra="allow", the generated schema includes"additionalProperties": true, which causes the API to reject the request with:Root Cause
The
_ensure_strict_json_schema()function (line 50) only setadditionalProperties = falsewhen the key was not already present:This conditional approach failed for Pydantic models with
extra="allow"because those models already have"additionalProperties": truein their schema.Solution
Modified the code to always set
additionalProperties = falsefor object types, regardless of whether the key already exists:Changes
src/openai/lib/_pydantic.py: Updated_ensure_strict_json_schema()to unconditionally setadditionalProperties = falsetest_pydantic_extra_allow()intests/lib/test_pydantic.pyto verify the fixTesting
Manual Testing
Reproduced the issue from #2740 and verified the fix resolves it:
Before fix:
After fix:
Test Coverage
Added comprehensive test that verifies:
extra="allow"correctly generateadditionalProperties: falseBackward Compatibility
This change is backward compatible:
extra="allow"already hadadditionalProperties: falseextra="allow"now work correctly (previously failed)References
extra="allow"#2740