fix: strip redundant id from $defs entries in toJSONSchema#5759
Conversation
Fixes colinhacks#5731 When a schema is annotated with .meta({ id: "Name" }), the id is used as the key in $defs so that other schemas can reference it. However, the id was also included verbatim in the definition body, producing redundant (and invalid) output like: "$defs": { "Inner": { "id": "Inner", ← redundant "type": "string" } } In extractToDef(), after copying the schema into seen.def, delete id from the definition body when it matches the defId — the id is already encoded as the $defs key name.
|
@pullfrog review |
There was a problem hiding this comment.
Reviewed — no issues found.
Task list (5/5 completed)
- Checkout PR and read the diff
- Read changed files and trace logic
- Check linked issue #5731 for context
- Verify snapshot updates match the code change
- Submit review
Claude Opus | 𝕏
The `id` in `.meta()` is a Zod-specific registration tag that controls $defs extraction — it is not user-facing JSON Schema metadata. Strip it from the output body in two places: 1. From each $defs entry where it equals the defId (already covered). 2. From the root schema where it equals the user-set metadata id. Move the strip to finalize() so that the override callback still observes `jsonSchema.id` on extracted definitions — preserves backward-compat for userland override handlers that read it. Adds explicit tests for: - $defs strip (draft-2020-12) - definitions strip (draft-04, where `id` is a reserved keyword) - root strip - override-callback observability
|
Hey @mibragimov — thanks for this. I pushed a follow-up commit that extends the fix slightly. Reasoning is that we treat
Snapshot diff for Happy to discuss any of this if you'd rather take a different approach. |
|
TL;DR — Strips the redundant Key changes
Summary | 2 files | 2 commits | base: Stripping the Zod
|
There was a problem hiding this comment.
No new issues. Reviewed the following changes:
- Moved
idstripping fromextractDefsintofinalize, keeping extraction logic focused on refs/defs and output cleanup in the finalize pass - Added root schema
idstripping — the previous version only stripped from$defsentries, but the registration tag also leaked onto root schemas with.meta({ id }) - Added four targeted tests:
$defsstripping (draft-2020-12),definitionsstripping (draft-04), root schema stripping, and a test confirmingidremains visible tooverridecallbacks before the strip runs - Updated existing inline snapshots to reflect the removal of leaked
idfields
Claude Opus | 𝕏
|
Merged 👍 The follow-up moves the Note: this comment was produced by an AI coding assistant. |
|
Landed in Zod 4.4 |
Problem
When a schema is annotated with
.meta({ id: "Name" }), theidis used as the key in$defsso that other schemas can reference it via$ref. However, theidwas also being included verbatim in the definition body, producing redundant output:{ "$defs": { "Inner": { "id": "Inner", "type": "string" } } }The presence of
idinside$defsentries is misleading — it looks like a JSON Schema$id, but it's just Zod's internalidtag. Theidis already encoded as the$defskey itself, so including it in the value is redundant.Fixes #5731
Solution
In
extractToDef(), after copying the schema intoseen.def, delete theidproperty from the definition body when it matchesdefId— the id is already encoded as the$defskey name.Before:
{ "$defs": { "Inner": { "id": "Inner", "type": "string" } } }After:
{ "$defs": { "Inner": { "type": "string" } } }Tests
Updated 6 existing snapshot tests that documented the old (buggy) behavior to reflect the correct output.