{"record":{"id":"a8a532e61b2b0c5d","repo":"can1357/oh-my-pi","slug":"expected-bound-after-comparator-in-this-src","errorCode":null,"errorMessage":"expected bound after comparator in \"${this.#src}\"","messagePattern":"expected bound after comparator in \"(.+?)\"","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":444,"sourceCode":"\tparseBounded(): IR {\n\t\tconst t = this.#peek();\n\t\tconst t1 = this.#peek(1);\n\t\tif ((t?.t === \"num\" || t?.t === \"date\") && t1?.t === \"op\" && (t1.v === \"<\" || t1.v === \"<=\")) {\n\t\t\tconst lo = t.v;\n\t\t\tthis.#pos += 2;\n\t\t\tlet node = this.#eatDivisor(this.parsePostfix());\n\t\t\tnode = applyBound(node, flip(t1.v), lo, this.#src);\n\t\t\tconst t2 = this.#peek();\n\t\t\tif (!(t2?.t === \"op\" && CMP[t2.v])) {\n\t\t\t\tthrow new OmpTypeError(`left bound requires a corresponding right bound in \"${this.#src}\"`);\n\t\t\t}\n\t\t\tif (t2.v === \">\" || t2.v === \">=\") {\n\t\t\t\tthrow new OmpTypeError(`right bound must use < or <= in \"${this.#src}\"`);\n\t\t\t}\n\t\t\tthis.#pos++;\n\t\t\tconst hi = this.#next();\n\t\t\tif (hi.t !== \"num\" && hi.t !== \"date\") {\n\t\t\t\tthrow new OmpTypeError(`expected bound after comparator in \"${this.#src}\"`);\n\t\t\t}\n\t\t\tnode = applyBound(node, t2.v, hi.v, this.#src);\n\t\t\treturn this.#eatArraySuffixes(node);\n\t\t}\n\t\tlet node = this.#eatDivisor(this.parsePostfix());\n\t\tconst t2 = this.#peek();\n\t\tif (t2?.t === \"op\" && t2.v === \"==\") {\n\t\t\tthis.#pos++;\n\t\t\tconst limit = this.#next();\n\t\t\tif (limit.t !== \"num\" && limit.t !== \"bigint\" && limit.t !== \"date\") {\n\t\t\t\tthrow new OmpTypeError(`expected literal after == in \"${this.#src}\"`);\n\t\t\t}\n\t\t\tnode = applyEquality(node, limit.v, this.#src);\n\t\t} else if (t2?.t === \"op\" && CMP[t2.v] && (this.#peek(1)?.t === \"num\" || this.#peek(1)?.t === \"date\")) {\n\t\t\tthis.#pos++;\n\t\t\tconst limit = this.#next() as Extract<Tok, { t: \"num\" | \"date\" }>;\n\t\t\tnode = applyBound(node, t2.v, limit.v, this.#src);\n\t\t\tnode = this.#eatArraySuffixes(node);","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L426-L462","documentation":"A comparison operator ('<', '<=', '>', '>=', '==') was parsed, but the following token is not a numeric or date literal — the bound value is missing or of the wrong kind. Bounds must be num or date tokens; identifiers, keywords, strings, or end-of-input after a comparator trigger this.","triggerScenarios":"'number > max' (identifier instead of literal), 'string > ', \"number == '5'\" (string literal where num/bigint/date required), 'number >' at end of input.","commonSituations":"Interpolating named constants into definitions ('number >= ${limit}' where limit is undefined or non-numeric); quoting numeric bounds by habit; truncation when the value part of the definition was lost.","solutions":["Replace the bound with a numeric or date literal: 'number > 5', 'Date < d\"2024-01-01\"'.","If the bound comes from a variable, stringify the raw number before interpolation, or attach the bound via the builder/object API instead.","Remove quotes from numeric bounds ('5' → 5).","If end-of-input, append the missing bound value after the comparator."],"exampleFix":"// before\nschema.parse(`number >= ${String(limit)}`); // limit is \"high\" -> throws\n// after\nschema.parse(`number >= ${Number(limit)}`); // or validate Number.isFinite(limit) first","handlingStrategy":"validation","validationCode":"function assertNumericBound(v) {\n  if (typeof v !== \"number\" || !Number.isFinite(v)) throw new Error(`bound must be a number, got ${v}`);\n  return String(v);\n}","typeGuard":"function isNumericLiteralToken(s) {\n  return /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/.test(s);\n}","tryCatchPattern":"try {\n  const schema = parse(def);\n} catch (e) {\n  if (String(e.message).includes(\"expected bound after comparator\")) {\n    // replace identifier/quoted bound with a plain numeric or date literal\n  }\n  throw e;\n}","preventionTips":["Never interpolate identifiers or quoted values where a bound literal is required.","Coerce and validate bounds with Number() before embedding them in definitions.","Keep bounds as raw digits or d\"...\" date literals."],"tags":["parser","bounds","schema-definition"],"backgroundTag":"missing-bound-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}