-
-
Notifications
You must be signed in to change notification settings - Fork 531
OpenAPI schema generation incorrectly marks nullable required fields as not required #4673
Description
Summary
Fields declared as field: int | None (nullable, no default) are not included in the OpenAPI schema's required array. Litestar conflates "nullable" (can be None) with "optional" (has a default), causing the generated schema to diverge from both Pydantic's own model_json_schema() output and the OpenAPI 3.1.0 specification.
Reproduction
from pydantic import BaseModel
from litestar import Litestar, get
class TestSchema(BaseModel):
required_non_nullable_field: int
required_nullable_field: int | None
optional_nullable_field: int | None = None
@get("/")
def get_test() -> TestSchema:
return TestSchema(required_non_nullable_field=2, required_nullable_field=1, optional_nullable_field=3)
app = Litestar(route_handlers=[get_test])Expected required array (matches Pydantic's model_json_schema()):
"required": ["required_non_nullable_field", "required_nullable_field"]Actual required array from Litestar's /schema/openapi.json:
"required": ["required_non_nullable_field"]Root Cause
The bug exists in four locations that each independently conflate nullability with optionality:
-
litestar/typing.py:242—FieldDefinition.is_requiredreturnsnot self.is_optional and ..., butis_optional(line 289) returnsTruewheneverNoneTypeis in the type args — i.e., whenever the type is nullable, regardless of whether a default exists. -
litestar/_openapi/schema_generation/plugins/dataclass.py:32— The required-field comprehension includesnot is_optional_union(type_hints[field.name]), which excludes nullable fields even when they have no default. -
litestar/_openapi/schema_generation/plugins/struct.py:48— Samenot is_optional_union(...)pattern as the dataclass plugin. -
litestar/plugins/pydantic/utils.py:251— Only wraps fields inNotRequiredwhendefault_factoryis set, but the downstreamFieldDefinition.is_requiredcheck (used atplugins/pydantic/plugins/schema.py:175) still fails due to issue Fix KeyError raised when annotating a view with return annotations #1.
Affected Model Types
All model types are affected: Pydantic (v1/v2), dataclasses, and msgspec Structs.
Versions
Confirmed on 2.16.0 and 2.21.0.