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

  1. Inspect `mergeErrorPath` and ensure both schemas agree on the value at that path (same literal, same array length, same primitive).
  2. 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

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


AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03). Data as JSON: /data/errors/0362a067cd955a44.json. Report an issue: GitHub.