can1357/oh-my-pi · error · OmpTypeError

string length intersection is unsatisfiable

Error message

string length intersection is unsatisfiable

What it means

Intersecting two string types intersects their length bounds: min becomes the larger of the two mins and max the smaller of the two maxes. If the resulting min exceeds the resulting max, no string can satisfy both, so the library throws instead of emitting an impossible type.

Source

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

							}
						: {}),
				};
			}
		}
		const extras =
			a.extras === "reject" || b.extras === "reject"
				? "reject"
				: a.extras === "delete" || b.extras === "delete"
					? "delete"
					: "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,

View on GitHub (pinned to 9690622007)

Solutions

  1. Widen the bounds so min <= max across both operands
  2. Remove the redundant length constraint from one operand
  3. Validate bounds on a single string() builder instead of splitting them across an intersection
  4. Catch OmpTypeError around intersect to report the conflicting bounds

Example fix

// before
intersect(string().min(10), string().max(5));
// after
intersect(string().min(3), string().max(10));
Defensive patterns

Strategy: validation

Validate before calling

function stringBoundsOk(specs) {
  const min = Math.max(...specs.map(s => s.min ?? 0));
  const max = Math.min(...specs.map(s => s.max ?? Infinity));
  return min <= max;
}

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 === 'string length intersection is unsatisfiable') {
    throw new Error(`String bounds conflict: ${describe(a)} vs ${describe(b)}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: intersect(string().min(10), string().max(5)) or intersecting a plain string with a constrained one whose bounds no longer overlap after a change.

Common situations: A validation rule tightened a min length while another rule capped max length; intersecting a URL-constrained string with a length cap that is too small; off-by-one in manually authored bounds (min > max on one side already).

Related errors


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