{"record":{"id":"929112432fb12d7f","repo":"can1357/oh-my-pi","slug":"numeric-bound-must-be-finite","errorCode":null,"errorMessage":"numeric bound must be finite","messagePattern":"numeric bound must be finite","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/type.ts","lineNumber":2467,"sourceCode":"\tif (b === undefined) return a;\n\treturn Math.max(a, b);\n}\n\nfunction minOf(a: number | undefined, b: number | undefined): number | undefined {\n\tif (a === undefined) return b;\n\tif (b === undefined) return a;\n\treturn Math.min(a, b);\n}\n\nfunction withLengthBound(ir: IR, side: \"min\" | \"max\", bound: number): IR {\n\tif (ir.k === \"array\" || ir.k === \"string\") {\n\t\treturn side === \"min\" ? { ...ir, min: bound } : { ...ir, max: bound };\n\t}\n\tthrow new OmpTypeError(`cannot apply length bound to ${ir.k}`);\n}\n\nfunction withNumericBound(ir: IR, side: \"min\" | \"max\", bound: number, exclusive = false): IR {\n\tif (!Number.isFinite(bound)) throw new OmpTypeError(\"numeric bound must be finite\");\n\tif (ir.k === \"number\") {\n\t\treturn side === \"min\" ? { ...ir, min: bound, xmin: exclusive } : { ...ir, max: bound, xmax: exclusive };\n\t}\n\tif (ir.k === \"union\") {\n\t\treturn { ...ir, members: ir.members.map(member => withNumericBound(member, side, bound, exclusive)) };\n\t}\n\tthrow new OmpTypeError(`cannot apply numeric bound to ${ir.k}`);\n}\ninterface GenericParameter {\n\treadonly name: string;\n\treadonly constraintDef?: unknown;\n}\n\ninterface GenericMeta {\n\treadonly parameters: readonly GenericParameter[];\n\tinstantiateIR(arguments_: readonly IR[]): IR;\n}\n","sourceCodeStart":2449,"sourceCodeEnd":2485,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/type.ts#L2449-L2485","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nnumber().max(Math.max(...items.map(i => i.cap))); // -Infinity when items is empty\n// after\nconst bound = Math.max(...items.map(i => i.cap));\nconst t = Number.isFinite(bound) ? number().max(bound) : number();","handlingStrategy":"validation","validationCode":"function finiteBound(n) {\n  return typeof n === 'number' && Number.isFinite(n) ? n : undefined;\n}\n// usage: number().max(finiteBound(computedMax)) — undefined omits the bound","typeGuard":"const isFiniteBound = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n);","tryCatchPattern":"try {\n  const t = number().min(b);\n} catch (err) {\n  if (err instanceof OmpTypeError && err.message === 'numeric bound must be finite') {\n    // fall back to unconstrained number() and warn\n  } else throw err;\n}","preventionTips":["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"],"tags":["types","number","bounds","validation","omptype"],"backgroundTag":"invalid-constraint-for-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}