{"id":"770e059bcd82d0fa","repo":"colinhacks/zod","slug":"cannot-overwrite-keys-on-object-schemas-containing","errorCode":null,"errorMessage":"Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.","messagePattern":"Cannot overwrite keys on object schemas containing refinements\\. Use `\\.safeExtend\\(\\)` instead\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/util.ts","lineNumber":672,"sourceCode":"  });\n\n  return clone(schema, def);\n}\n\nexport function extend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): any {\n  if (!isPlainObject(shape)) {\n    throw new Error(\"Invalid input to extend: expected a plain object\");\n  }\n\n  const checks = schema._zod.def.checks;\n  const hasChecks = checks && checks.length > 0;\n  if (hasChecks) {\n    // Only throw if new shape overlaps with existing shape\n    // Use getOwnPropertyDescriptor to check key existence without accessing values\n    const existingShape = schema._zod.def.shape;\n    for (const key in shape) {\n      if (Object.getOwnPropertyDescriptor(existingShape, key) !== undefined) {\n        throw new Error(\"Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.\");\n      }\n    }\n  }\n\n  const def = mergeDefs(schema._zod.def, {\n    get shape() {\n      const _shape = { ...schema._zod.def.shape, ...shape };\n      assignProp(this, \"shape\", _shape); // self-caching\n      return _shape;\n    },\n  });\n  return clone(schema, def) as any;\n}\n\nexport function safeExtend(schema: schemas.$ZodObject, shape: schemas.$ZodShape): any {\n  if (!isPlainObject(shape)) {\n    throw new Error(\"Invalid input to safeExtend: expected a plain object\");\n  }","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/util.ts#L654-L690","documentation":"Thrown by `.extend()` when the schema has refinement checks AND the new shape tries to overwrite a key that already exists (guard at util.ts:666-673). Overwriting a field that a refinement depends on would silently break cross-field validation, so the library refuses and redirects to `.safeExtend()`, which intentionally bypasses the check.","triggerScenarios":"Calling `Schema.extend({ existingKey: z.string() })` where `Schema` was built with `.refine()/.superRefine()` touching `existingKey`.","commonSituations":"Overriding a field type on a validated schema (e.g. widening `id` from `z.string()` to `z.string().uuid()`); reusing a base schema with refinements and customizing fields per endpoint; inheriting a shared validated schema.","solutions":["Use `.safeExtend({ key: newSchema })` if you intentionally accept the refinement-risk tradeoff.","Move the refinement off the base schema and reattach it after `.extend()`.","Define the base object without refinements, extend it, then layer `.refine()` on each variant."],"exampleFix":"// before\nconst Base = z.object({ id: z.string() }).refine(d => d.id.length > 0);\nconst Wide = Base.extend({ id: z.string().uuid() }); // throws\n\n// after\nconst Wide = Base.safeExtend({ id: z.string().uuid() });","handlingStrategy":"validation","validationCode":"function hasOverlaps(s: z.core.$ZodObject, shape: Record<string, unknown>): boolean {\n  const existing = s._zod.def.shape;\n  return Object.keys(shape).some(k => Object.getOwnPropertyDescriptor(existing, k) !== undefined);\n}\nif (hasRefinements(Schema) && hasOverlaps(Schema, newShape)) {\n  // use safeExtend intentionally\n}","typeGuard":"function isRefinementFree(s: z.core.$ZodObject): boolean {\n  return !s._zod.def.checks?.length;\n}","tryCatchPattern":"try { Out = Schema.extend(newShape); }\ncatch (e) {\n  if (e instanceof Error && /safeExtend/.test(e.message)) Out = Schema.safeExtend(newShape);\n  else throw e;\n}","preventionTips":["Keep refinements off base schemas that need to be extended.","If you knowingly accept the risk, call `.safeExtend()` upfront instead of `.extend()`."],"tags":["zod","object-schema","extend","refinement"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}