colinhacks/zod · error · Error
.partial() cannot be used on object schemas containing refin
Error message
.partial() cannot be used on object schemas containing refinements
What it means
Thrown by `.partial()` when the target object schema has refinement checks (guard at util.ts:726-728). Making fields optional would change the input shape that refinements validate against, risking silent invalidation, so `.partial()` refuses. There is no `safePartial` variant — you must restructure.
Source
Thrown at packages/zod/src/v4/core/util.ts:729
get catchall() {
return b._zod.def.catchall;
},
checks: b._zod.def.checks ?? [],
});
return clone(a, def) as any;
}
export function partial(
Class: SchemaClass<schemas.$ZodOptional> | null,
schema: schemas.$ZodObject,
mask: object | undefined
): any {
const currDef = schema._zod.def;
const checks = currDef.checks;
const hasChecks = checks && checks.length > 0;
if (hasChecks) {
throw new Error(".partial() cannot be used on object schemas containing refinements");
}
const def = mergeDefs(schema._zod.def, {
get shape() {
const oldShape = schema._zod.def.shape;
const shape: Writeable<schemas.$ZodShape> = { ...oldShape };
if (mask) {
for (const key in mask) {
if (!(key in oldShape)) {
throw new Error(`Unrecognized key: "${key}"`);
}
if (!(mask as any)[key]) continue;
// if (oldShape[key]!._zod.optin === "optional") continue;
shape[key] = Class
? new Class({
type: "optional",
innerType: oldShape[key]!,View on GitHub (pinned to 912f0f51b0)
Solutions
- Move refinements off the base object, call `.partial()` on the bare object, then reattach refinements to the result.
- Define the create schema without cross-field checks, derive `.partial()` for updates, and add refinements per variant.
- Use a separate update schema entirely instead of deriving with `.partial()`.
Example fix
// before
const User = z.object({ id: z.string(), email: z.string() }).refine(d => d.id !== d.email);
const Update = User.partial(); // throws
// after
const Base = z.object({ id: z.string(), email: z.string() });
const Update = Base.partial().refine(d => d.id !== d.email); Defensive patterns
Strategy: type-guard
Validate before calling
function hasRefinements(s: z.core.$ZodObject): boolean {
return !!s._zod.def.checks?.length;
}
if (hasRefinements(User)) {
// restructure: bare object -> partial -> reattach refine
} Type guard
function isRefinementFree(s: z.core.$ZodObject): boolean {
return !s._zod.def.checks?.length;
} Prevention
- Define base objects without refinements; `.partial()` the bare object; re-add refinements after.
- Maintain separate create/update schemas instead of deriving update from a validated create schema.
When it happens
Trigger: Calling `Schema.partial()` or `Schema.partial({ field: true })` on a schema that has `.refine()/.superRefine()` attached.
Common situations: Building an update/patch schema from a validated create schema via `.partial()`; sharing a single source-of-truth object with refinements across POST/PATCH handlers.
Related errors
- .omit() cannot be used on object schemas containing refineme
- Cannot overwrite keys on object schemas containing refinemen
- .merge() cannot be used on object schemas containing refinem
- Unrecognized key: "${key}"
- Invalid input to extend: expected a plain object
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/f7b87486aa94bc94.json.
Report an issue: GitHub.