can1357/oh-my-pi · error · OmpTypeError
numeric bound must be finite
Error message
numeric bound must be finite
What it means
withNumericBound rejects non-finite bounds (NaN, Infinity, -Infinity) before applying them to a numeric IR. Bounds must be finite so the resulting range is meaningful; passing Infinity as an 'unbounded' marker is not allowed.
Source
Thrown at packages/omptype/src/type.ts:2467
if (b === undefined) return a;
return Math.max(a, b);
}
function minOf(a: number | undefined, b: number | undefined): number | undefined {
if (a === undefined) return b;
if (b === undefined) return a;
return Math.min(a, b);
}
function withLengthBound(ir: IR, side: "min" | "max", bound: number): IR {
if (ir.k === "array" || ir.k === "string") {
return side === "min" ? { ...ir, min: bound } : { ...ir, max: bound };
}
throw new OmpTypeError(`cannot apply length bound to ${ir.k}`);
}
function withNumericBound(ir: IR, side: "min" | "max", bound: number, exclusive = false): IR {
if (!Number.isFinite(bound)) throw new OmpTypeError("numeric bound must be finite");
if (ir.k === "number") {
return side === "min" ? { ...ir, min: bound, xmin: exclusive } : { ...ir, max: bound, xmax: exclusive };
}
if (ir.k === "union") {
return { ...ir, members: ir.members.map(member => withNumericBound(member, side, bound, exclusive)) };
}
throw new OmpTypeError(`cannot apply numeric bound to ${ir.k}`);
}
interface GenericParameter {
readonly name: string;
readonly constraintDef?: unknown;
}
interface GenericMeta {
readonly parameters: readonly GenericParameter[];
instantiateIR(arguments_: readonly IR[]): IR;
}
View on GitHub (pinned to 9690622007)
Solutions
- Replace non-finite bounds with undefined (omit the bound) instead of Infinity sentinels
- Sanitize computed values: check Number.isFinite(bound) before passing it
- Fix the source computation producing NaN (guard division/parse failures)
- Catch OmpTypeError and fall back to an unconstrained number
Example fix
// before number().max(Math.max(...items.map(i => i.cap))); // -Infinity when items is empty // after const bound = Math.max(...items.map(i => i.cap)); const t = Number.isFinite(bound) ? number().max(bound) : number();
Defensive patterns
Strategy: validation
Validate before calling
function finiteBound(n) {
return typeof n === 'number' && Number.isFinite(n) ? n : undefined;
}
// usage: number().max(finiteBound(computedMax)) — undefined omits the bound Type guard
const isFiniteBound = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n);
Try / catch
try {
const t = number().min(b);
} catch (err) {
if (err instanceof OmpTypeError && err.message === 'numeric bound must be finite') {
// fall back to unconstrained number() and warn
} else throw err;
} Prevention
- Use undefined to mean 'no bound'; never pass Infinity/NaN as a sentinel
- Sanitize computed bounds with Number.isFinite before building the schema
- Guard the upstream math (division, parsing, Math.min/max over possibly-empty arrays) that produces the bound
When it happens
Trigger: number().min(Infinity), number().max(-Infinity), number().min(Number.NaN); or computed bounds like Math.max() over an empty list (-Infinity) or a division by zero producing NaN fed into a builder.
Common situations: Deriving bounds from config data where a field is missing/NaN; using Number.MAX_VALUE vs Infinity confusion aside, sentinel values like Infinity meaning 'no limit'; empty-array Math.min/max results.
Related errors
- string length intersection is unsatisfiable
- numeric range intersection is unsatisfiable
- array length intersection is unsatisfiable
- cannot apply length bound to ${ir.k}
- Invalid number: ${rawValue}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/929112432fb12d7f.
Report an issue: GitHub.