Skip to content

Fix minItems for all-optional array-like Structs - #1124

Open
gaoflow wants to merge 1 commit into
msgspec:mainfrom
gaoflow:fix-json-schema-array-like-defaults
Open

Fix minItems for all-optional array-like Structs#1124
gaoflow wants to merge 1 commit into
msgspec:mainfrom
gaoflow:fix-json-schema-array-like-defaults

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Problem

For an array_like=True Struct where every user field has a default, msgspec.json.schema reports minItems one too high. An untagged Struct gets minItems: 1 even though msgspec.json.decode accepts [] and fills all defaults; a tagged Struct similarly gets 2 even though a tag-only array is valid. Generated schemas therefore reject payloads accepted by msgspec itself.

The trailing-default loop stored the zero-based enumerate index and later used it as a count. When the loop never encountered a required field, that count was one short.

Fix

Count trailing optional fields explicitly before calculating minItems. The existing required-field and empty-Struct boundaries remain unchanged.

The regression test covers both tagged and untagged Structs and includes a default_factory, while checking the generated schema against the public decoder contract.

Testing

  • just test tests/unit/test_schema.py — 124 passed, 2 skipped
  • just test — 6412 passed, 113 skipped
  • just check — lint, format, and spelling checks passed

@codspeed-hq

codspeed-hq Bot commented Jul 16, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 10.99%

⚡ 1 improved benchmark
✅ 138 untouched benchmarks
⏩ 135 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation test_pickle_load[arm] 1.8 ms 1.6 ms +10.99%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing gaoflow:fix-json-schema-array-like-defaults (58ae07b) with main (a1ebbcd)

Open in CodSpeed

Footnotes

  1. 135 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant