Skip to content

fix: OpenAPI schema missing minItems/maxItems for msgspec Meta on collections#4605

Open
worksbyfriday wants to merge 4 commits intolitestar-org:mainfrom
worksbyfriday:fix-msgspec-collection-min-items
Open

fix: OpenAPI schema missing minItems/maxItems for msgspec Meta on collections#4605
worksbyfriday wants to merge 4 commits intolitestar-org:mainfrom
worksbyfriday:fix-msgspec-collection-min-items

Conversation

@worksbyfriday
Copy link
Copy Markdown

Summary

Fixes #4514.

When using Annotated[list[T], Meta(min_length=N)] on a msgspec Struct field, the OpenAPI schema generation did not include minItems/maxItems, even though:

  • Runtime validation worked correctly (msgspec rejects short arrays)
  • msgspec.json.schema() correctly generated minItems

The constraint metadata was lost at two boundaries:

  1. litestar/plugins/core/_msgspec.py: kwarg_definition_from_field() extracted min_length/max_length for string/bytes types (lines 65-77) but not for collection types (ListType, SetType, FrozenSetType, VarTupleType). Added collection type handling that maps min_lengthmin_items and max_lengthmax_items.

  2. litestar/typing.py: _annotated_types_extractor() handled annotated_types.MinLen/MaxLen but not msgspec.Meta (which is a separate class, not an annotated_types subclass). Added a branch for msgspec.Meta that extracts all constraint attributes, correctly mapping length constraints to items constraints for sequence containers.

Before

"category_ids": {
  "items": {"type": "string", "format": "uuid"},
  "type": "array"
}

After

"category_ids": {
  "items": {"type": "string", "format": "uuid"},
  "type": "array",
  "minItems": 1
}

Test plan

  • Added test_create_schema_from_msgspec_annotated_collection_type verifying minItems/maxItems for list and set fields
  • Verified reporter's exact reproduction case produces correct schema
  • Verified existing test_create_schema_from_msgspec_annotated_type still passes (no regression on int/str/bytes fields)

@worksbyfriday worksbyfriday requested review from a team as code owners February 22, 2026 06:01
@worksbyfriday worksbyfriday changed the title Fix OpenAPI schema missing minItems/maxItems for msgspec Meta on collections fix: OpenAPI schema missing minItems/maxItems for msgspec Meta on collections Feb 22, 2026
kwargs["pattern"] = "[[:ascii:]]"
elif meta.func == str.isdigit: # pragma: no cover # coverage quirk: It expects a jump here for branch coverage
kwargs["pattern"] = "[[:digit:]]"
elif isinstance(meta, msgspec.Meta):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be handled here, since it's an implementation specific thing. It should be handled in the plugin. You can check how it's handled for other msgspec constraints / Pydantic, within their respective plugins.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Removed the msgspec.Meta handling from _annotated_types_extractor. The plugin's kwarg_definition_from_field now handles collection types — msgspec.inspect already unwraps Meta into ListType(min_length=...), so the plugin just needs to extract those fields.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.85%. Comparing base (3dc3507) to head (019184b).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4605   +/-   ##
=======================================
  Coverage   97.85%   97.85%           
=======================================
  Files         297      297           
  Lines       15344    15347    +3     
  Branches     1722     1723    +1     
=======================================
+ Hits        15015    15018    +3     
  Misses        188      188           
  Partials      141      141           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@worksbyfriday
Copy link
Copy Markdown
Author

Both review items addressed:

  1. Moved msgspec.Meta handling to the plugin (commit bde4c46)
  2. Merged the collection test into the existing test case (commit 777b4f6)

Ready for another look.

@github-actions
Copy link
Copy Markdown

Documentation preview will be available shortly at https://litestar-org.github.io/litestar-docs-preview/4605

worksbyfriday and others added 4 commits February 28, 2026 13:09
…ields

When using `Annotated[list[T], Meta(min_length=N)]` on a msgspec Struct
field, the OpenAPI schema generation did not include `minItems`/`maxItems`,
even though runtime validation and msgspec's own schema generation handled
them correctly.

Two fixes:

1. `litestar/plugins/core/_msgspec.py`: The `kwarg_definition_from_field()`
   function extracted `min_length`/`max_length` for string/bytes types but
   not for collection types (ListType, SetType, FrozenSetType, VarTupleType).
   Added collection type handling that maps `min_length` → `min_items` and
   `max_length` → `max_items`.

2. `litestar/typing.py`: The `_annotated_types_extractor()` function handled
   `annotated_types.MinLen`/`MaxLen` but not `msgspec.Meta`. Added a branch
   for `msgspec.Meta` that extracts all constraint attributes (gt, ge, lt,
   le, multiple_of, min_length, max_length, pattern), correctly mapping
   length constraints to items constraints for sequence containers.

Fixes litestar-org#4514
Per review: msgspec-specific handling belongs in the plugin, not in
the general annotated types extractor. The plugin already extracts
min_length/max_length from collection types via msgspec.inspect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move default_field after required fields to satisfy msgspec's
constraint that optional fields must follow required ones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@provinzkraut provinzkraut force-pushed the fix-msgspec-collection-min-items branch from 019184b to b834398 Compare February 28, 2026 12:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants