{"record":{"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":2609,"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":2591,"sourceCodeEnd":2627,"githubUrl":"https://github.com/colinhacks/zod/blob/2d90846af918af9602e088812d63a035d47cdbe4/packages/zod/src/v4/core/schemas.ts#L2591-L2627","documentation":"Thrown by handleIntersectionResults after calling mergeValues(left.value, right.value) when the two parsed intersection halves cannot be structurally merged (mergeValues returns { valid: false, mergeErrorPath }). mergeValues only knows how to combine plain objects (recursively) and same-length arrays; any other combination (string ∩ number, object ∩ primitive, differing scalar types) is unmergable, and the recorded path (JSON.stringified) pinpoints the deepest conflict.","triggerScenarios":"z.intersection(z.string(), z.number()); z.intersection(z.object({a:z.string()}), z.array(z.string())); arrays of differing lengths; nested field conflicts like z.object({a: z.string()}) intersected with z.object({a: z.number()}) — the parse succeeds on both sides but merging the values fails.","commonSituations":"Combining two branded/refined scalar schemas whose underlying types differ; intersecting an object with a record; upgrading from a version that silently took one side to one that enforces structural compatibility; user composes schemas from multiple modules that were not designed to overlap.","solutions":["Inspect mergeErrorPath to find the exact conflicting field and align the types on both sides.","If only one side should win, replace z.intersection() with z.pipe() or a manual .transform().","Ensure both halves agree on the type of every shared key (object intersections) or that scalars match.","For arrays, ensure both sides expect the same length and element structure."],"exampleFix":"// before\nconst S = z.intersection(z.string(), z.number());\n// after — pick one scalar\nconst S = z.string();\n// or merge compatible object shapes\nconst S = z.intersection(\n  z.object({ id: z.string() }),\n  z.object({ id: z.string(), name: z.string() })\n);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return z.intersection(A, B).parse(input);\n} catch (e) {\n  if (/Unmergable intersection/.test((e as Error).message)) {\n    // Align types in A and B, or fall back to a single schema / pipe\n    return A.parse(input);\n  }\n  throw e;\n}","preventionTips":["Only intersect schemas whose parsed outputs are structurally mergeable (objects with compatible keys, or matching scalars).","Inspect mergeErrorPath to localize the conflict.","Prefer z.pipe() when you need one side to win rather than a true merge.","Unit-test intersection parsing with representative inputs."],"tags":["intersection","runtime","merge","types"],"backgroundTag":null,"analyzedSha":"2d90846af918af9602e088812d63a035d47cdbe4","analyzedAt":"2026-08-11T01:21:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}