can1357/oh-my-pi · error · OmpTypeError

intersection has no satisfiable branches

Error message

intersection has no satisfiable branches

What it means

This error is thrown by the intersection algorithm in packages/omptype when combining two intersection-typed values: every candidate branch combination fails with an OmpTypeError, so no satisfiable member remains. The library treats an intersection whose branches are all impossible as a type-construction error rather than silently producing `never`, so it fails fast at type build/parse time.

Source

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

		}
		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);
	if (a.k === "object" && b.k === "object") {
		const props = [...a.props];
		for (const bp of b.props) {
			const index = props.findIndex(prop => prop.key === bp.key);
			if (index < 0) props.push(bp);
			else {
				const ap = props[index];
				const required = (!ap.opt && !ap.hasDefault) || (!bp.opt && !bp.hasDefault);
				if (ap.hasDefault && bp.hasDefault && !Object.is(ap.def, bp.def)) {
					throw new OmpTypeError(
						`ParseError: Invalid intersection of default values ${String(ap.def)} & ${String(bp.def)}`,

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove or relax one of the intersected types so at least one branch combination is satisfiable
  2. Check that both operands share the same value domain (string vs string, number vs number) before intersecting
  3. Catch OmpTypeError around the intersect call and surface which pair of types failed
  4. If the intersection is intentionally impossible, use a union or a single type instead

Example fix

// before
const t = intersect(string().min(5), string().max(2));
// after
const t = intersect(string().min(1), string().max(2));
Defensive patterns

Strategy: try-catch

Validate before calling

function canIntersect(a, b) {
  try { intersect(a, b); return true; } catch (e) {
    return e instanceof OmpTypeError ? false : throw e;
  }
}

Type guard

const isOmpTypeError = (e: unknown): e is OmpTypeError => e instanceof OmpTypeError;

Try / catch

let combined;
try {
  combined = intersect(typeA, typeB);
} catch (err) {
  if (err instanceof OmpTypeError) {
    throw new Error(`Cannot intersect ${describe(typeA)} with ${describe(typeB)}: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the intersect/intersection helper (or building a schema that intersects two types) where every pairwise intersect(branch, other) call throws an OmpTypeError — e.g. intersecting string with number, or object shapes with conflicting required keys.

Common situations: Merging two config schemas that declare incompatible base types for the same option; combining a base type with a refinement whose domain no longer overlaps after a library upgrade; intersecting a tuple with mismatched element types.

Related errors


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