Skip to content

fix(v4): clone Map and Set in shallowClone to prevent shared state#5855

Merged
colinhacks merged 1 commit into
colinhacks:mainfrom
artur-seppa:fix/default-mutable-clone
Apr 28, 2026
Merged

fix(v4): clone Map and Set in shallowClone to prevent shared state#5855
colinhacks merged 1 commit into
colinhacks:mainfrom
artur-seppa:fix/default-mutable-clone

Conversation

@artur-seppa
Copy link
Copy Markdown
Contributor

Problem

When using .default() with mutable values like Map or Set, every call to
.parse(undefined) returns the same reference. Mutations on one parse result
leak into subsequent parses:

const schema = z.map(z.string(), z.number()).default(new Map());

const result1 = schema.parse(undefined);
result1.set("key", 42);

const result2 = schema.parse(undefined);
console.log(result2.size); // 1 — should be 0

This already worked correctly for plain objects and arrays via shallowClone,
but Map and Set fell through to return o (same reference).

Fix

Extended shallowClone in util.ts to cover Map and Set:

if (o instanceof Map) return new Map(o);
if (o instanceof Set) return new Set(o);

Tests

Added four tests to default.test.ts:

shallow clone returns distinct instances for Map and Set
mutations on one parse result do not affect another (both directions)
Fixes #5826

@colinhacks
Copy link
Copy Markdown
Owner

@pullfrog review

Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

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

Reviewed — no issues found.

Task list (5/5 completed)
  • Read the PR diff
  • Review util.ts changes (shallowClone)
  • Review test changes
  • Check for edge cases and correctness
  • Submit review

Pullfrog  | View workflow run | Using Claude Opus𝕏

@colinhacks colinhacks merged commit 34f6015 into colinhacks:main Apr 28, 2026
6 of 8 checks passed
@colinhacks
Copy link
Copy Markdown
Owner

Landed in Zod 4.4

@artur-seppa artur-seppa deleted the fix/default-mutable-clone branch April 30, 2026 17:35
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.

.default() shallow-copies

3 participants