{"record":{"id":"aaba958f3dd2ab1b","repo":"can1357/oh-my-pi","slug":"left-bound-requires-a-corresponding-right-bound-in","errorCode":null,"errorMessage":"left bound requires a corresponding right bound in \"${this.#src}\"","messagePattern":"left bound requires a corresponding right bound in \"(.+?)\"","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":436,"sourceCode":"\t\treturn { k: \"intersection\", members };\n\t}\n\n\t/**\n\t * `NUM CMP base (CMP NUM)?` or `base (CMP NUM)?`, with `[]*` postfix on the\n\t * base AND after a trailing bound — `string>0[]` is an array of bounded\n\t * strings, matching ArkType precedence (bounds bind tighter than `[]`).\n\t */\n\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\") {","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L418-L454","documentation":"A left-bounded range ('lo < base' or 'lo <= base') was written, but after the base the parser did not find a comparison operator to close the range. Two-sided ranges like '0 < number < 10' must end with a right bound; a bare '0 < number' is rejected so an incomplete range never silently becomes one-sided.","triggerScenarios":"Definitions like '0 < number' (missing ' < 10'), '0 < number[]', or '0 < string' followed by end-of-input or a non-comparator token.","commonSituations":"Thinking the left-bound form alone expresses a minimum (in omptype it must be completed on the right, or rewritten as 'number > 0'); truncation during string building; mixing syntax from other validators where '0 < number' is valid.","solutions":["Complete the range: '0 < number < 100'.","If only a lower bound is wanted, flip it to postfix form: 'number > 0' or 'number >= 0'.","Check that the string wasn't truncated — append the missing ' < N' portion.","Note that '>' / '>=' as the right comparator is also rejected (see the companion error); only '<' or '<=' may close the range."],"exampleFix":"// before\nschema.parse(\"0 < number\");\n// after\nschema.parse(\"0 < number < 100\"); // or \"number > 0\"","handlingStrategy":"validation","validationCode":"// left-bound form must contain a closing upper comparator\nif (/^\\s*-?\\d+(?:\\.\\d+)?\\s*[<=]\\s*\\S+/.test(def) && !/[<>]=?\\s*-?\\d+(?:\\.\\d+)?[^<>=]*$/.test(def)) {\n  // might be one-sided; prefer rewriting or completing the range\n}","typeGuard":null,"tryCatchPattern":"try {\n  const schema = parse(def);\n} catch (e) {\n  if (String(e.message).includes(\"left bound requires a corresponding right bound\")) {\n    // rewrite as \"base > lo\" or append \" < hi\"\n  }\n  throw e;\n}","preventionTips":["Prefer postfix bounds ('number > 0') unless you truly need a two-sided range.","When using 'lo < base' form, always finish with '<' or '<=' and a numeric/date literal.","Lint definitions for 'lo < base' patterns lacking a trailing bound."],"tags":["parser","bounds","range-syntax"],"backgroundTag":"incomplete-range-bounds","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}