colinhacks/zod · error · Error
Unmergable intersection. Error path: ${JSON.stringify(merged
Error message
Unmergable intersection. Error path: ${JSON.stringify(merged.mergeErrorPath)} What it means
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.
Source
Thrown at packages/zod/src/v4/core/schemas.ts:2592
unrecKeys.get(k)!.r = true;
}
} else {
result.issues.push(iss);
}
}
// Report only keys unrecognized by BOTH sides
const bothKeys = [...unrecKeys].filter(([, f]) => f.l && f.r).map(([k]) => k);
if (bothKeys.length && unrecIssue) {
result.issues.push({ ...unrecIssue, keys: bothKeys });
}
if (util.aborted(result)) return result;
const merged = mergeValues(left.value, right.value);
if (!merged.valid) {
throw new Error(`Unmergable intersection. Error path: ` + `${JSON.stringify(merged.mergeErrorPath)}`);
}
result.value = merged.data;
return result;
}
/////////////////////////////////////////
/////////////////////////////////////////
////////// //////////
////////// $ZodTuple //////////
////////// //////////
/////////////////////////////////////////
/////////////////////////////////////////
export interface $ZodTupleDef<
T extends util.TupleItems = readonly $ZodType[],
Rest extends SomeType | null = $ZodType | null,
> extends $ZodTypeDef {View on GitHub (pinned to 912f0f51b0)
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.
Example fix
// before — two sides set different constants on the same field
const I = z.intersection(
z.object({ role: z.literal('admin') }),
z.object({ role: z.literal('user') })
);
I.parse({ role: 'admin' }); // throws: Unmergable intersection. Error path: ["role"]
// after — model as a union instead of an impossible intersection
const U = z.union([
z.object({ role: z.literal('admin') }),
z.object({ role: z.literal('user') }),
]); Defensive patterns
Strategy: try-catch
Validate before calling
import { z } from 'zod';
// Before intersecting, verify the two schemas agree on shared literal fields.
function canIntersect(a, b) {
const va = a._zod?.propValues ?? {};
const vb = b._zod?.propValues ?? {};
for (const k of Object.keys(va)) {
if (vb[k]) for (const x of va[k]) if (vb[k].has(x)) return true; // ok, shared value
// if no overlap and both non-empty, intersection is unsatisfiable for that key
}
return true;
} Try / catch
try {
I.parse(input);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Unmergable intersection')) {
// mergeErrorPath is in the message; resolve the conflicting field by removing it from one side
// or switch from intersection to union
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cannot mix number and bigint in multiple_of check.
- Invalid UUID version: "${def.version}"
- Invalid discriminated union option at index "${def.options.i
- Invalid discriminated union option at index "${def.options.i
- Duplicate discriminator value "${String(v)}"
AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03).
Data as JSON: /data/errors/0362a067cd955a44.json.
Report an issue: GitHub.