{"record":{"id":"f15f8874fad9fc7b","repo":"can1357/oh-my-pi","slug":"name-must-be-finite","errorCode":null,"errorMessage":"${name} must be finite","messagePattern":"(.+?) must be finite","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/typebox.ts","lineNumber":200,"sourceCode":"\treturn compatSchema;\n}\n\nfunction applyMeta<T>(schema: RuntimeType<T>, opts?: Meta): CompatRuntime<T> {\n\tlet result = schema;\n\tconst description = opts?.description ?? opts?.title;\n\tif (description !== undefined) result = result.describe(description);\n\tif (opts && Object.hasOwn(opts, \"default\")) result = result.default(opts.default as T);\n\treturn withLegacyCompat(result);\n}\n\nfunction withJsonSchemaKeywords<T>(schema: CompatRuntime<T>, keywords: Record<string, unknown>): CompatRuntime<T> {\n\tconst emitBase = schema.toJsonSchema.bind(schema);\n\tschema.toJsonSchema = options => ({ ...emitBase(options), ...keywords });\n\treturn schema;\n}\n\nfunction checkFiniteOption(name: string, value: number | undefined): void {\n\tif (value !== undefined && !Number.isFinite(value)) throw new OmpTypeError(`${name} must be finite`);\n}\n\nfunction tString(opts?: StringOpts): TString {\n\tcheckFiniteOption(\"minLength\", opts?.minLength);\n\tcheckFiniteOption(\"maxLength\", opts?.maxLength);\n\tlet schema = asRuntime<string>(type.raw(opts?.format === \"url\" || opts?.format === \"uri\" ? \"string.url\" : \"string\"));\n\tif (opts?.minLength !== undefined) schema = schema.atLeastLength(opts.minLength);\n\tif (opts?.maxLength !== undefined) schema = schema.atMostLength(opts.maxLength);\n\tif (opts?.pattern !== undefined) {\n\t\tlet regex: RegExp;\n\t\ttry {\n\t\t\tregex = new RegExp(opts.pattern);\n\t\t} catch {\n\t\t\tthrow new OmpTypeError(`invalid regular expression pattern ${JSON.stringify(opts.pattern)}`);\n\t\t}\n\t\tschema = schema.narrow((value, ctx) => regex.test(value) || ctx.mustBe(`a string matching ${opts.pattern}`));\n\t}\n\tif (opts?.format !== undefined && opts.format !== \"url\" && opts.format !== \"uri\") {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/typebox.ts#L182-L218","documentation":"tString/tNumber/tArray option builders validate that numeric constraint options (minLength, maxLength, minimum, maximum, exclusive bounds, multipleOf, length, etc.) are finite numbers via `checkFiniteOption`. Passing NaN, Infinity, or -Infinity for any such option throws `<name> must be finite` at construction time rather than producing a broken schema.","triggerScenarios":"`tString({ maxLength: Infinity })`, `tString({ minLength: NaN })`, `tArray(el, { length: Infinity })`, or a computed bound like `tNumber({ maximum: someMax })` where `someMax` is NaN/Infinity (e.g. result of `Math.max()` on empty input, division by zero, parsed untrusted config).","commonSituations":"Deriving limits from unvalidated JSON config or env vars (`parseInt` returning NaN); computing `Infinity` as a default max; arithmetic overflows when converting byte limits to string limits.","solutions":["Validate/derive the bound before passing it: ensure it is a finite number (`Number.isFinite`).","If the limit is intentionally unbounded, omit the option entirely instead of passing Infinity.","Fix the computation producing NaN (empty array input, undefined config value, failed parseInt)."],"exampleFix":"// before\ntString({ maxLength: Number(process.env.MAX_LEN) }); // NaN if unset\n// after\nconst raw = Number(process.env.MAX_LEN);\ntString(raw !== undefined && Number.isFinite(raw) ? { maxLength: raw } : undefined);","handlingStrategy":"validation","validationCode":"function finiteOpt(n: number | undefined): number | undefined {\n  if (n === undefined) return undefined;\n  if (!Number.isFinite(n)) throw new RangeError(`bound must be finite, got ${n}`);\n  return n;\n}\n// use: tString({ maxLength: finiteOpt(rawMaxLength) })","typeGuard":"function isFiniteBound(v: unknown): v is number {\n  return typeof v === \"number\" && Number.isFinite(v);\n}","tryCatchPattern":"try {\n  const schema = tString({ maxLength: opts.maxLength });\n} catch (err) {\n  if (err instanceof Error && /must be finite$/.test(err.message)) {\n    throw new Error(`Invalid schema option from config: ${err.message}`);\n  }\n  throw err;\n}","preventionTips":["Always run config-derived numeric options through Number.isFinite before use.","Treat Infinity as 'no constraint' — omit the option instead of passing it.","Parse limits with a helper that returns `number | undefined` (undefined on unparsable input) instead of raw Number()."],"tags":["omptype","schema-construction","numeric-options","invalid-argument"],"backgroundTag":"non-finite-number-option","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}