Description
A recursive PEP 695 type alias used as a handler annotation crashes OpenAPI schema generation with RecursionError.
SchemaCreator.for_type_alias_type unwraps the alias's __value__ and recurses into it with no cycle guard, so a self-referential alias (e.g. a JSON type) expands forever:
https://github.com/litestar-org/litestar/blob/v2.23.0/litestar/_openapi/schema_generation/schema.py — for_type_alias_type calls for_field_definition(... annotation=field_definition.annotation.__value__ ...).
Litestar already guards self-referential models (#2429 / #2869, via a registered $ref), but that guard was never extended to the type-alias path added in #3715. So recursive models work, while recursive type aliases do not.
Downstream I've worked around it by patching for_type_alias_type to track in-progress aliases and return a free-form Schema() on revisit, which breaks the cycle. I can open a PR upstream if a maintainer confirms the preferred shape (free-form vs. $ref).
URL to code causing the issue
No response
MCVE
Steps to reproduce
from litestar import Litestar, get
type JSON = None | bool | str | float | int | list[JSON] | dict[str, JSON]
@get("/")
async def handler() -> JSON:
return {}
app = Litestar([handler])
app.openapi_schema.to_schema() # RecursionError
Screenshots
No response
Logs
Litestar Version
- litestar 2.23.0
- Python 3.14
Platform
Description
A recursive PEP 695
typealias used as a handler annotation crashes OpenAPI schema generation withRecursionError.SchemaCreator.for_type_alias_typeunwraps the alias's__value__and recurses into it with no cycle guard, so a self-referential alias (e.g. aJSONtype) expands forever:https://github.com/litestar-org/litestar/blob/v2.23.0/litestar/_openapi/schema_generation/schema.py —
for_type_alias_typecallsfor_field_definition(... annotation=field_definition.annotation.__value__ ...).Litestar already guards self-referential models (#2429 / #2869, via a registered
$ref), but that guard was never extended to the type-alias path added in #3715. So recursive models work, while recursive type aliases do not.Downstream I've worked around it by patching
for_type_alias_typeto track in-progress aliases and return a free-formSchema()on revisit, which breaks the cycle. I can open a PR upstream if a maintainer confirms the preferred shape (free-form vs.$ref).URL to code causing the issue
No response
MCVE
Steps to reproduce
Screenshots
No response
Logs
Litestar Version
Platform