Skip to content

Bug: OpenAPI schema missing minItems for list fields with msgspec.Meta(min_length=N) #4514

@renjianguo666

Description

@renjianguo666

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:

  1. Runtime validation works correctly (msgspec rejects arrays shorter than N)
  2. msgspec's own msgspec.json.schema() correctly generates minItems

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_length

However, 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
                pass

URL to code causing the issue

No response

MCVE

Steps to reproduce

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Screenshots

No response

Logs


Litestar Version

2.18

Platform

  • Linux
  • Mac
  • Windows
  • Other (Please specify in the description above)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug 🐛This is something that is not working as expected

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions