Skip to content

fix(pydantic): recurse into oneOf variants in strict JSON schema#2987

Open
alvinttang wants to merge 2 commits intoopenai:mainfrom
alvinttang:fix/strict-schema-oneOf
Open

fix(pydantic): recurse into oneOf variants in strict JSON schema#2987
alvinttang wants to merge 2 commits intoopenai:mainfrom
alvinttang:fix/strict-schema-oneOf

Conversation

@alvinttang
Copy link

Summary

_ensure_strict_json_schema() in src/openai/lib/_pydantic.py recurses into anyOf and allOf variants but skips oneOf. Pydantic v2 generates oneOf (not anyOf) for discriminated unions — i.e. fields using discriminator=...:

class Cat(BaseModel):
    pet_type: Literal["cat"]
    meows: int

class Dog(BaseModel):
    pet_type: Literal["dog"]
    barks: float

class PetOwner(BaseModel):
    name: str
    pet: Union[Cat, Dog] = Field(discriminator="pet_type")

This produces a schema with "oneOf": [{"$ref": "#/$defs/Cat"}, {"$ref": "#/$defs/Dog"}] in the pet property. Any inline object schemas nested inside oneOf (rather than via $ref) would not receive additionalProperties: false or the required array, causing the OpenAI API to reject the schema with:

Invalid schema for response_format: 'additionalProperties' is required to be supplied and to be false.

Fix

Add oneOf handling that mirrors the existing anyOf logic (7 lines).

Test plan

  • Added test_discriminated_union_oneOf regression test
  • Verified anyOf behavior is unchanged
  • Verified $defs inside discriminated unions still get strict treatment

🤖 Generated with Claude Code

Pydantic v2 generates oneOf (not anyOf) for discriminated unions
(fields using discriminator=...). The _ensure_strict_json_schema
function already recurses into anyOf and allOf variants but skips
oneOf, so inline object schemas inside oneOf never receive
additionalProperties: false or the required array -- causing the
OpenAI API to reject the schema.

Add oneOf handling that mirrors the existing anyOf logic.
@alvinttang alvinttang requested a review from a team as a code owner March 18, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant