Skip to content

deepPartial throws ".partial() cannot be used on object schemas containing refinements" with zod ≥ 4.3.0 #572

Description

@gak10100

Summary

deepPartial from @traversable/zod throws on any schema whose tree contains a refined object (.refine() / .superRefine()), because it internally calls zod's .partial() — which zod has rejected on object schemas containing refinements since v4.3.0.

Reproduction

import { z } from 'zod'
import { deepPartial } from '@traversable/zod/deep-partial'

// ❌ Error: .partial() cannot be used on object schemas containing refinements
deepPartial(z.object({ a: z.string() }).refine(() => true))

// ❌ Same error when the refinement is nested anywhere in the tree:
deepPartial(z.object({ inner: z.object({ a: z.string() }).refine(() => true) }))

// ✅ Works without a refinement:
deepPartial(z.object({ a: z.string() }))

Standalone:

mkdir repro && cd repro && npm init -y && npm pkg set type=module
npm install zod@4.4.3 @traversable/zod@0.0.57
# put the snippet above in repro.mjs
node repro.mjs

Actual

Error: .partial() cannot be used on object schemas containing refinements
    at Module.partial (zod/v4/core/util.js)
    at @traversable/zod/src/deep-partial.ts:91

Expected

deepPartial should produce a deep-partial schema for trees that contain refined objects — e.g. by partialing the underlying object shape and dropping the refinement (a .refine() predicate can't be preserved through a structural partial anyway), instead of calling .partial() directly on the refined wrapper.

This shows up for any nested refined field — in our case a shared LocalizedString = z.object({...}).refine(...) used across many models, so deepPartial(SomeModel) fails at module-load for every model that embeds it.

Root cause / zod version boundary

zod introduced the .partial()-on-refinements restriction in 4.3.0:

zod z.object({...}).refine(...).partial()
≤ 4.2.1 ✅ allowed
4.3.0 → 4.4.3 (latest) ❌ throws

@traversable/zod's peer is zod: 4, so any consumer on current zod (4.3+/4.4) hits this.

Environment

  • @traversable/zod 0.0.57 (latest)
  • zod 4.4.3 (also reproduces on 4.3.0)
  • node v24.12.0

Possible fix

In deep-partial.ts, when a node is an object schema carrying refinements, partial the inner shape / unwrap to the underlying ZodObject def and rebuild, rather than calling .partial() on the refined wrapper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions