-
-
Notifications
You must be signed in to change notification settings - Fork 492
Description
Description
Description
When using msgspec.Struct with Annotated[list[T], Meta(min_length=N)], Litestar's OpenAPI schema generation does not include the minItems constraint, even though:
- Runtime validation works correctly (msgspec rejects arrays shorter than N)
- msgspec's own
msgspec.json.schema()correctly generatesminItems
Reproduction
Minimal Example
from typing import Annotated
from uuid import UUID
from litestar import Litestar, post
from msgspec import Meta, Struct
class ArticleCreateSchema(Struct, frozen=True):
title: Annotated[str, Meta(min_length=1, max_length=255)]
category_ids: Annotated[list[UUID], Meta(min_length=1)] # <-- This should have minItems=1
@post("/articles")
async def create_article(data: ArticleCreateSchema) -> dict:
return {"status": "ok"}
app = Litestar([create_article])
if __name__ == "__main__":
import json
schema = app.openapi_schema.to_schema()
article_schema = schema["components"]["schemas"]["ArticleCreateSchema"]
print(json.dumps(article_schema, indent=2))Output (Actual)
{
"properties": {
"title": {
"type": "string",
"maxLength": 255,
"minLength": 1
},
"category_ids": {
"items": {
"type": "string",
"format": "uuid"
},
"type": "array"
}
},
"required": ["category_ids", "title"],
"title": "ArticleCreateSchema",
"type": "object"
}Expected Output
{
"properties": {
"title": {
"type": "string",
"maxLength": 255,
"minLength": 1
},
"category_ids": {
"items": {
"type": "string",
"format": "uuid"
},
"type": "array",
"minItems": 1
}
},
"required": ["category_ids", "title"],
"title": "ArticleCreateSchema",
"type": "object"
}Proof that msgspec handles this correctly
import msgspec
from msgspec import Meta, Struct
from typing import Annotated
from uuid import UUID
class TestSchema(Struct):
category_ids: Annotated[list[UUID], Meta(min_length=1)]
schema = msgspec.json.schema(TestSchema)
print(schema)
# Output: {'$ref': '#/$defs/TestSchema', '$defs': {'TestSchema': {'title': 'TestSchema', 'type': 'object', 'properties': {'category_ids': {'type': 'array', 'items': {'type': 'string', 'format': 'uuid'}, 'minItems': 1}}, 'required': ['category_ids']}}}Note: msgspec correctly outputs 'minItems': 1 in its schema.
Environment
- Python: 3.11.8
- Litestar: 2.18.0
- msgspec: 0.20.0
- OS: Windows 11
Analysis
Looking at the Litestar source code, there is logic in litestar/typing.py that should handle this:
kwargs["min_items"] = meta.min_lengthHowever, this conversion is not being triggered when processing msgspec Struct fields with Meta(min_length=N) on list types.
Impact
This causes issues for frontend code generation tools (like @hey-api/openapi-ts with Zod plugin) that rely on the OpenAPI schema to generate validation rules. The generated Zod schemas are missing .min(N) constraints for array fields.
Workaround
Currently, we're using a post-processing script to patch the generated OpenAPI schema:
def fix_array_min_items(schema_dict: dict) -> None:
schemas = schema_dict.get("components", {}).get("schemas", {})
for schema_name, schema in schemas.items():
for prop_name, prop in schema.get("properties", {}).items():
if prop.get("type") == "array" and "minItems" not in prop:
# Manually add minItems based on known constraints
passURL to code causing the issue
No response
MCVE
Steps to reproduce
- Go to '...'
- Click on '....'
- Scroll down to '....'
- See error
Screenshots
No response
Logs
Litestar Version
2.18
Platform
- Linux
- Mac
- Windows
- Other (Please specify in the description above)