{"record":{"id":"287a70ab7357c833","repo":"can1357/oh-my-pi","slug":"right-bound-must-use-or-in-this-src","errorCode":null,"errorMessage":"right bound must use < or <= in \"${this.#src}\"","messagePattern":"right bound must use < or <= in \"(.+?)\"","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/ir.ts","lineNumber":439,"sourceCode":"\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\") {\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);","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/ir.ts#L421-L457","documentation":"In a two-sided range 'lo CMP base CMP2 hi', the right comparator must be '<' or '<=' — writing '0 < number > 10' or '0 < number >= 10' is contradictory (cannot be satisfied) and is rejected at parse time. The left side already establishes the lower bound with flipped semantics, so only upper-bound comparators are legal on the right.","triggerScenarios":"Definitions like '0 < number > 10' or '1 <= number >= 5' where the second comparator points the wrong way.","commonSituations":"Transliterating chained comparisons from prose ('greater than 0 and greater than 10'); typos when editing both bounds in the same direction; copying a lower-bound expression into the right-hand slot.","solutions":["Use '<' or '<=' for the right comparator: '0 < number < 10'.","Express the intended (possibly odd) constraint as an intersection of two one-sided bounds if truly needed: 'number > 0 & number > 10' — though verify it isn't contradictory.","Re-read the range in reading order: left value is the minimum, right value is the maximum.","Validate programmatically-built ranges so lo <= hi and comparators are generated, not hand-typed."],"exampleFix":"// before\nschema.parse(\"0 < number > 10\");\n// after\nschema.parse(\"0 < number < 10\");","handlingStrategy":"validation","validationCode":"// in a two-sided range the right comparator must be < or <=\nconst m = def.match(/^\\s*-?\\d+(?:\\.\\d+)?\\s*[<=]\\s*\\S+\\s*([<>=]+)/);\nif (m && (m[1] === \">\" || m[1] === \">=\")) throw new Error(`wrong right comparator ${m[1]} in: ${def}`);","typeGuard":null,"tryCatchPattern":"try {\n  const schema = parse(def);\n} catch (e) {\n  if (String(e.message).includes(\"right bound must use < or <=\")) {\n    // flip the right comparator to < or <=\n  }\n  throw e;\n}","preventionTips":["Read two-sided ranges as 'min < base < max' and keep both comparators pointing right.","Never chain '>' after a left bound; express independent lower bounds as separate intersections.","Generate ranges programmatically to keep comparator direction consistent."],"tags":["parser","bounds","range-syntax"],"backgroundTag":"invalid-range-comparator","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}