can1357/oh-my-pi · error · OmpTypeError

union intersection invariant failed

Error message

union intersection invariant failed

What it means

In intersectResolved(), after detecting that at least one operand is a union, the code recomputes which operand was the union; if neither branch actually has k === 'union' despite the earlier guard, an internal invariant is broken and omptype throws. This is effectively an assertion — hitting it means corrupt or non-normalized IR reached the intersection (e.g. a hand-built IR or a failed alias resolution).

Source

Thrown at packages/omptype/src/type.ts:2026

		if (a.fn !== b.fn || a.out !== b.out) {
			throw new OmpTypeError("intersection of distinct morphs is indeterminate");
		}
		return { ...a, input: intersect(a.input, b.input) };
	}
	if (a.k === "morph") return { ...a, input: intersect(a.input, b) };
	if (b.k === "morph") return { ...b, input: intersect(a, b.input) };
	if (a.k === "sub" && a.schema.hasSteps) {
		if (b.k === "sub" && b.schema.hasSteps) {
			if (a.schema === b.schema) return a;
			throw new OmpTypeError("intersection of distinct morphs is indeterminate");
		}
		const schema = a.schema as InternalType;
		return embed(makeType(intersect(schema.ir, b), schema[kSteps], metaOf(schema)));
	}
	if (b.k === "sub" && b.schema.hasSteps) return intersect(b, a);
	if (a.k === "union" || b.k === "union") {
		const union = a.k === "union" ? a : b.k === "union" ? b : undefined;
		if (union === undefined) throw new OmpTypeError("union intersection invariant failed");
		const branches = union.members;
		const other = a.k === "union" ? b : a;
		const members: IR[] = [];
		for (const branch of branches) {
			try {
				members.push(intersect(branch, other));
			} catch (error) {
				if (!(error instanceof OmpTypeError)) throw error;
			}
		}
		if (members.length === 0) throw new OmpTypeError("intersection has no satisfiable branches");
		return members.length === 1 ? members[0] : { k: "union", members };
	}
	if (a.k === "lit") {
		if (walk(b, a.v) instanceof OmpErrors) throw new OmpTypeError("literal is excluded by the intersection");
		return a;
	}
	if (b.k === "lit") return intersect(b, a);

View on GitHub (pinned to 9690622007)

Solutions

  1. Deduplicate omptype so only one version exists (bun pm ls | grep omptype; fix duplicate installs)
  2. Never construct or mutate IR objects directly — only use public builders
  3. Rebuild the offending schema with current public API instead of copying cached/deserialized IR
  4. If reproducible with public API only, report it as a bug with a minimal repro

Example fix

// before
// manually mutated schema.ir to a union-like object
schema.ir = { k: 'union', members: [...] }
// after
const T = union(memberA, memberB) // build via API
intersect(T, other)
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure operands come from the public API and one package version:
// bun pm ls | grep omptype  → expect exactly one version
function isWellFormedIR(ir) {
  return ir && typeof ir.k === 'string' && (ir.k !== 'union' || Array.isArray(ir.members));
}

Type guard

function isUnionIR(ir): ir is { k: 'union'; members: unknown[] } {
  return typeof ir === 'object' && ir !== null && ir.k === 'union' && Array.isArray(ir.members);
}

Try / catch

try {
  return intersect(a, b);
} catch (err) {
  if (err instanceof OmpTypeError && err.message.includes('union intersection invariant')) {
    logger.error('omptype IR invariant violated — likely version skew or manual IR mutation');
    throw err; // do not swallow; fix the duplicate-install or rebuild the schema
  }
  throw err;
}

Prevention

When it happens

Trigger: Feeding a custom/foreign IR object into embed/intersect; an alias resolving to something mutated after construction; a bug or version mismatch inside omptype's IR normalization.

Common situations: Patching IR internals or monkey-patching schema objects; mixing omptype versions where IR shapes changed (e.g. two copies of the package in node_modules); deserializing schemas across versions.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/5f28678d9cc842da. Report an issue: GitHub.