can1357/oh-my-pi · error · OmpTypeError
cannot apply numeric bound to ${ir.k}
Error message
cannot apply numeric bound to ${ir.k} What it means
withNumericBound() applies min/max bounds only to number IR nodes (or unions, by mapping each member). If the resolved IR kind is anything else — string, boolean, object, array, record, etc. — the library throws OmpTypeError because numeric bounds are meaningless there. This is a compile-time-mistake surfaced at runtime: you called .min()/.max() (or equivalent) on a type that isn't a number.
Source
Thrown at packages/omptype/src/type.ts:2474
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;
}
const GENERIC_META = Symbol("omptype.generic");
/** Callable runtime generic returned by `type("<t>", def)` and `type.generic(...)`. */
export type Generic = (...arguments_: readonly unknown[]) => BaseType;
interface RuntimeGeneric extends Generic {
readonly [GENERIC_META]: GenericMeta;View on GitHub (pinned to 9690622007)
Solutions
- Ensure the base definition is numeric, e.g. type('number').min(0) instead of type('string').min(0)
- If the type is a union, make every member numeric or bound each numeric member individually
- Use the correct constraint API for non-numeric kinds (string length, array length) instead of numeric bounds
- Catch OmpTypeError at schema-construction time and surface a clearer message to schema authors
Example fix
// before
const t = type('string').min(3); // throws
// after
const t = type('string').atLeastLength(3);
const n = type('number').min(3); // numeric bound on number is fine Defensive patterns
Strategy: validation
Validate before calling
function assertNumericBounded(def: string) {
if (!/^number\b|union<.*number.*>/.test(def.trim())) {
throw new Error(`numeric bounds require a numeric definition, got: ${def}`);
}
} Type guard
function isNumberIR(ir: { k: string }): ir is { k: 'number'; min?: number; max?: number } {
return ir.k === 'number' || ir.k === 'union';
} Try / catch
try {
const t = type(def).min(bound);
} catch (err) {
if (err instanceof OmpTypeError && err.message.startsWith('cannot apply numeric bound')) {
throw new Error(`Schema ${def} is not numeric; use length/range APIs instead`);
}
throw err;
} Prevention
- Only call .min/.max on definitions you know resolve to number
- Prefer kind-specific APIs (atLeastLength for strings) over numeric bounds
- Add a unit test per schema that exercises bound construction
When it happens
Trigger: Calling a numeric bound method (min/max style) on a type built from a non-numeric definition, e.g. type('string').min(...) via a path that goes through withNumericBound, or on a union containing non-numeric members.
Common situations: Refactoring a schema from number to string/integer-like and forgetting to drop the bound; applying bounds to a generic/aliased definition whose underlying kind isn't number; piping a user-supplied definition into a numeric-bound helper.
Related errors
- anthropic-messages: ${data.summary}
- Schema contains a circular object graph — cannot enforce str
- Schema node has no type, combinator, or $ref — cannot enforc
- Validation failed for tool "${toolCall.name}":\n${errors}\n\
- ClinePass model catalog response is missing clinePass
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6a94ea3aa73b54f7.
Report an issue: GitHub.