Skip to content

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

Merged
Siyet merged 1 commit into
msgspec:mainfrom
binggao1230:fix-json-schema-array-like-defaults
Sep 13, 2026
Merged

Siyet merged 1 commit into
msgspec:mainfrom
binggao1230:fix-json-schema-array-like-defaults

Conversation

@binggao1230

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

codspeed 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. ↩

@fallenmi fallenmi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verified exact head 58ae07bcad83e518d749b7580a69cf91f7b3f4de.

  • Exact base a1ebbcdcf65b794370956e41c8c925cc366ed6f0 failed 8/50 matrix cases: every tagged or untagged array-like Struct with zero required and 1–4 defaulted fields advertised minItems one too high, while the decoder accepted the minimal payload.
  • The head and a clean current-main integration pass all 50 combinations (0–4 required × 0–4 defaulted × tag on/off), with schema minItems matching the decoder minimum.
  • Exact-head full unit suite: 6,052 passed / 473 skipped. Current-main integration: 6,052 passed / 473 skipped. Ruff check/format and git diff --check are clean; all live upstream checks are green.

The counter correction also preserves the mixed required/default and zero-field boundaries. Approving this unchanged head.

Reviewed with OpenAI Codex assistance

@Siyet Siyet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thx for the fix! The schema now matches the decoder when every field has a default

@Siyet
Siyet added this pull request to the merge queue Sep 13, 2026
Merged via the queue into msgspec:main with commit c5c3012 Sep 13, 2026
27 checks passed
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.

3 participants