can1357/oh-my-pi · error · OmpTypeError

numeric range intersection is unsatisfiable

Error message

numeric range intersection is unsatisfiable

What it means

Intersecting two number types intersects their ranges (min = max of mins, max = min of maxs) while tracking exclusive bounds. The throw fires when the resulting range is empty: min > max, or min === max with an exclusive bound on either side (so no value can equal the single point).

Source

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

					: "keep";
		const index = a.index && b.index ? intersect(a.index, b.index) : (a.index ?? b.index);
		return { k: "object", props, index, extras };
	}
	if (a.k === "string" && b.k === "string") {
		const min = maxOf(a.min, b.min);
		const max = minOf(a.max, b.max);
		if (min !== undefined && max !== undefined && min > max) {
			throw new OmpTypeError("string length intersection is unsatisfiable");
		}
		return { k: "string", min, max, url: a.url || b.url };
	}
	if (a.k === "number" && b.k === "number") {
		const min = maxOf(a.min, b.min);
		const max = minOf(a.max, b.max);
		const xmin = min !== undefined && ((a.min === min && a.xmin === true) || (b.min === min && b.xmin === true));
		const xmax = max !== undefined && ((a.max === max && a.xmax === true) || (b.max === max && b.xmax === true));
		if (min !== undefined && max !== undefined && (min > max || (min === max && (xmin || xmax)))) {
			throw new OmpTypeError("numeric range intersection is unsatisfiable");
		}
		if (a.divisor !== undefined && b.divisor !== undefined && a.divisor !== b.divisor) {
			return { k: "intersection", members: [a, b] };
		}
		return {
			k: "number",
			int: a.int || b.int,
			divisor: a.divisor ?? b.divisor,
			min,
			max,
			xmin,
			xmax,
		};
	}
	if (a.k === "array" && b.k === "array") {
		const min = maxOf(a.min, b.min);
		const max = minOf(a.max, b.max);
		if (min !== undefined && max !== undefined && min > max) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Widen one range so a non-empty overlap exists
  2. Drop the redundant range constraint from one operand
  3. Use exclusive vs inclusive bounds deliberately: change gt/lt to gte/lte if a boundary value is legal
  4. Catch OmpTypeError and report both ranges to the user

Example fix

// before
intersect(number().gt(5), number().lt(5));
// after
intersect(number().gte(5), number().lt(5));
Defensive patterns

Strategy: validation

Validate before calling

function numberRangeOk(specs) {
  const min = Math.max(...specs.map(s => s.min ?? -Infinity));
  const max = Math.min(...specs.map(s => s.max ?? Infinity));
  if (min > max) return false;
  if (min === max && (specs.some(s => s.xmin) || specs.some(s => s.xmax))) return false;
  return true;
}

Type guard

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

Try / catch

try {
  const t = intersect(a, b);
} catch (err) {
  if (err instanceof OmpTypeError && err.message === 'numeric range intersection is unsatisfiable') {
    throw new Error(`Numeric ranges do not overlap: ${describe(a)} vs ${describe(b)}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: intersect(number().min(10), number().max(5)); or intersect(number().gt(5), number().lt(5)) — point range excluded by exclusivity; incompatible divisors are handled separately (kept as an intersection), so this is purely range emptiness.

Common situations: Two validation layers each constraining the same numeric option from opposite directions (min from config A, max from config B); exclusive bounds squeezed to a single point after an edit; percentage/0-1 range checks colliding with absolute caps.

Related errors


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