{"id":"0362a067cd955a44","repo":"colinhacks/zod","slug":"unmergable-intersection-error-path-json-string","errorCode":null,"errorMessage":"Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)}","messagePattern":"Unmergable intersection\\. Error path: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/schemas.ts","lineNumber":2592,"sourceCode":"        unrecKeys.get(k)!.r = true;\n      }\n    } else {\n      result.issues.push(iss);\n    }\n  }\n\n  // Report only keys unrecognized by BOTH sides\n  const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k);\n  if (bothKeys.length && unrecIssue) {\n    result.issues.push({ ...unrecIssue, keys: bothKeys });\n  }\n\n  if (util.aborted(result)) return result;\n\n  const merged = mergeValues(left.value, right.value);\n\n  if (!merged.valid) {\n    throw new Error(`Unmergable intersection. Error path: ` + `${JSON.stringify(merged.mergeErrorPath)}`);\n  }\n\n  result.value = merged.data;\n  return result;\n}\n\n/////////////////////////////////////////\n/////////////////////////////////////////\n//////////                     //////////\n//////////      $ZodTuple      //////////\n//////////                     //////////\n/////////////////////////////////////////\n/////////////////////////////////////////\n\nexport interface $ZodTupleDef<\n  T extends util.TupleItems = readonly $ZodType[],\n  Rest extends SomeType | null = $ZodType | null,\n> extends $ZodTypeDef {","sourceCodeStart":2574,"sourceCodeEnd":2610,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/schemas.ts#L2574-L2610","documentation":"Thrown at parse time inside `handleIntersectionResults` when the two sides of a `z.intersection(A, B)` produce output values that cannot be deep-merged. The internal `mergeValues` recursively merges objects element-by-element and requires arrays to be equal length and primitives to be strictly equal (or equal Dates); any conflict at a shared path makes the intersection unsatisfiable. The reported `mergeErrorPath` points at the first conflicting key/index.","triggerScenarios":"Intersecting two schemas whose outputs assign different literal values to the same field (e.g. `z.object({ a: z.literal(1) })` ∩ `z.object({ a: z.literal(2) })`), or two arrays of differing length, or a primitive vs object at the same path. Transforms that rewrite values on both sides commonly trigger this.","commonSituations":"Composing a base schema with an override schema that sets a different constant; using `.transform()` on both sides of an intersection; intersecting branded/refined schemas whose post-transform shapes collide.","solutions":["Inspect `mergeErrorPath` and ensure both schemas agree on the value at that path (same literal, same array length, same primitive).","If the conflict is intentional, remove the intersection and model the variants with `z.union([...])` or a discriminated union instead."],"exampleFix":"// before — two sides set different constants on the same field\nconst I = z.intersection(\n  z.object({ role: z.literal('admin') }),\n  z.object({ role: z.literal('user') })\n);\nI.parse({ role: 'admin' }); // throws: Unmergable intersection. Error path: [\"role\"]\n\n// after — model as a union instead of an impossible intersection\nconst U = z.union([\n  z.object({ role: z.literal('admin') }),\n  z.object({ role: z.literal('user') }),\n]);","handlingStrategy":"try-catch","validationCode":"import { z } from 'zod';\n// Before intersecting, verify the two schemas agree on shared literal fields.\nfunction canIntersect(a, b) {\n  const va = a._zod?.propValues ?? {};\n  const vb = b._zod?.propValues ?? {};\n  for (const k of Object.keys(va)) {\n    if (vb[k]) for (const x of va[k]) if (vb[k].has(x)) return true; // ok, shared value\n    // if no overlap and both non-empty, intersection is unsatisfiable for that key\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n  I.parse(input);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Unmergable intersection')) {\n    // mergeErrorPath is in the message; resolve the conflicting field by removing it from one side\n    // or switch from intersection to union\n  }\n  throw e;\n}","preventionTips":["Avoid intersecting schemas that set different constants on the same field.","Keep transforms off the intersection sides, or ensure they produce identical values on shared paths.","Prefer a single object schema with optional fields over intersecting many small invariants."],"tags":["intersection","parse-time","validation"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}