can1357/oh-my-pi · error · OmpTypeError

literal is excluded by intersection

Error message

literal is excluded by intersection

What it means

parseIntersection detected a numeric literal intersected with a number constraint it cannot satisfy: integer-ness, a % divisor, or a min/max bound. E.g. '2.5 & number.integer', '3 & number % 2', '0 & number > 1'. The result would be the never type, so the library refuses at parse time rather than producing a schema that matches nothing.

Source

Thrown at packages/omptype/src/ir.ts:413

		return { k: "union", members };
	}

	parseIntersection(): IR {
		const first = this.parseBounded();
		if (!this.#eatOp("&")) return first;
		const members = [first, this.parseBounded()];
		while (this.#eatOp("&")) members.push(this.parseBounded());
		const literal = members.find((member): member is Extract<IR, { k: "lit" }> => member.k === "lit");
		if (literal && typeof literal.v === "number") {
			for (const member of members) {
				if (
					member.k === "number" &&
					((member.int && !Number.isInteger(literal.v)) ||
						(member.divisor !== undefined && literal.v % member.divisor !== 0) ||
						(member.min !== undefined && (member.xmin ? literal.v <= member.min : literal.v < member.min)) ||
						(member.max !== undefined && (member.xmax ? literal.v >= member.max : literal.v > member.max)))
				) {
					throw new OmpTypeError("literal is excluded by intersection");
				}
			}
			return literal;
		}
		return { k: "intersection", members };
	}

	/**
	 * `NUM CMP base (CMP NUM)?` or `base (CMP NUM)?`, with `[]*` postfix on the
	 * base AND after a trailing bound — `string>0[]` is an array of bounded
	 * strings, matching ArkType precedence (bounds bind tighter than `[]`).
	 */
	parseBounded(): IR {
		const t = this.#peek();
		const t1 = this.#peek(1);
		if ((t?.t === "num" || t?.t === "date") && t1?.t === "op" && (t1.v === "<" || t1.v === "<=")) {
			const lo = t.v;
			this.#pos += 2;

View on GitHub (pinned to 9690622007)

Solutions

  1. Make the literal satisfy the constraint: use an integer for '& number.integer', a multiple for '% n', and a value inside the bounds.
  2. If the constant was meant to be independent, replace '&' with a union '|' or remove the redundant constraint.
  3. Recompute bounds/divisor so they're consistent with the literal, ideally deriving both from one source constant.
  4. If never is genuinely intended, use the explicit 'never' keyword instead of a contradictory intersection.

Example fix

// before
schema.parse("3 & number % 2"); // never
// after
schema.parse("3 & number % 1"); // or just 3, or 4 & number % 2
Defensive patterns

Strategy: validation

Validate before calling

function literalFits(v, { int, divisor, min, max, xmin, xmax }) {
  if (int && !Number.isInteger(v)) return false;
  if (divisor !== undefined && v % divisor !== 0) return false;
  if (min !== undefined && (xmin ? v <= min : v < min)) return false;
  if (max !== undefined && (xmax ? v >= max : v > max)) return false;
  return true;
}

Try / catch

try {
  const schema = parse(def);
} catch (e) {
  if (String(e.message) === "literal is excluded by intersection") {
    // drop the conflicting constraint or correct the literal
  }
  throw e;
}

Prevention

When it happens

Trigger: Intersections of a number literal with 'number.integer' when the literal has a fraction; with a '% n' divisor when literal % n !== 0; or with a bound (>, >=, <, <=, possibly flipped via the left-bound form) that excludes the literal.

Common situations: Combining a constant with a refinement written by a different code path (template-built constraints drifting out of sync with the literal); refactoring bounds without updating co-declared literals; generically composing 'value & number >= minValue' where value < minValue.

Related errors


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