diff --git a/src/openai/lib/_pydantic.py b/src/openai/lib/_pydantic.py index 3cfe224cb1..02bd2bcdf0 100644 --- a/src/openai/lib/_pydantic.py +++ b/src/openai/lib/_pydantic.py @@ -47,7 +47,10 @@ def _ensure_strict_json_schema( _ensure_strict_json_schema(definition_schema, path=(*path, "definitions", definition_name), root=root) 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 # object types diff --git a/tests/lib/test_pydantic.py b/tests/lib/test_pydantic.py index 754a15151c..43006ac37c 100644 --- a/tests/lib/test_pydantic.py +++ b/tests/lib/test_pydantic.py @@ -409,3 +409,28 @@ def test_nested_inline_ref_expansion() -> None: "additionalProperties": False, } ) + + +def test_pydantic_extra_allow() -> None: + """Test that models with extra='allow' correctly set additionalProperties to False. + + Regression test for issue #2740. + The OpenAI API requires additionalProperties=false for structured output, + even when Pydantic models use extra="allow" which generates True by default. + """ + from pydantic import ConfigDict + + class MyClassWithExtraAllow(BaseModel): + model_config = ConfigDict(extra="allow") + field: str = Field(description="A test field") + + schema = to_strict_json_schema(MyClassWithExtraAllow) + + # The schema must have additionalProperties set to False + assert schema.get("additionalProperties") == False, \ + "additionalProperties must be False for API compliance, even with extra='allow'" + + # Verify the rest of the schema is correct + assert schema["type"] == "object" + assert "field" in schema["properties"] + assert schema["required"] == ["field"]