can1357/oh-my-pi · error · OmpTypeError
Malformed number literal '${raw}'
Error message
Malformed number literal '${raw}' What it means
The omptype string-definition tokenizer encountered a sequence starting with a digit or '-' that does not form a valid numeric or bigint literal. A number must round-trip exactly: canonical integer or decimal form, no leading zeros, not -0, and String(Number(raw)) === raw. This prevents silently accepting sloppy numeric syntax (e.g. '1.2.3', '01', '1e3', '1_000') that would otherwise parse to an unintended value.
Source
Thrown at packages/omptype/src/ir.ts:248
const flags = src.slice(j + 1, end);
try {
toks.push({ t: "regex", v: new RegExp(source, flags) });
} catch {
throw new OmpTypeError(`invalid regular expression "${src.slice(i, end)}"`);
}
i = end;
continue;
}
if ((c >= "0" && c <= "9") || (c === "-" && i + 1 < n && src[i + 1] >= "0" && src[i + 1] <= "9")) {
let j = i + 1;
while (j < n && /[\w.+-]/.test(src[j])) j++;
const raw = src.slice(i, j);
if (/^-?(?:0|[1-9]\d*)n$/.test(raw) && raw !== "-0n") {
toks.push({ t: "bigint", v: BigInt(raw.slice(0, -1)) });
} else {
const valid =
/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(raw) && !Object.is(Number(raw), -0) && String(Number(raw)) === raw;
if (!valid) throw new OmpTypeError(`Malformed number literal '${raw}'`);
toks.push({ t: "num", v: Number(raw) });
}
i = j;
continue;
}
if (/[a-zA-Z_$]/.test(c)) {
let j = i + 1;
while (j < n && /[\w.$]/.test(src[j])) j++;
toks.push({ t: "id", v: src.slice(i, j) });
i = j;
continue;
}
if (c === "<" || c === ">") {
if (src[i + 1] === "=") {
toks.push({ t: "op", v: `${c}=` });
i += 2;
} else {
toks.push({ t: "op", v: c });View on GitHub (pinned to 9690622007)
Solutions
- Rewrite the literal in plain canonical decimal form: '1e5' → '100000', '007' → '7', '0x10' → '16'.
- Remove unit suffixes or separators from the numeric portion; express units elsewhere in your schema.
- If the value comes from code, pre-format it so String(Number(v)) === v (e.g. use plain integer strings), or pass the value as a runtime default (= literal) instead of embedding it.
- If a bigint is intended, use the exact canonical form '5n' (never '-0n', which is explicitly rejected).
Example fix
// before
const def = `number > ${min}`; // min = 1e6 -> "number > 1000000" ok, but min=1e21 -> "number > 1e+21" throws
// after
const def = `number > ${min.toFixed(0)}`; // always plain decimal digits Defensive patterns
Strategy: validation
Validate before calling
function isValidNumberLiteral(s) {
return /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(s) && !Object.is(Number(s), -0) && String(Number(s)) === s;
}
if (!isValidNumberLiteral(String(min))) throw new Error(`bad literal: ${min}`); Try / catch
try {
const schema = parse(def);
} catch (e) {
if (String(e.message).startsWith("Malformed number literal")) {
// fall back to a sanitized literal: String(Number(raw)) or toFixed(0)
}
throw e;
} Prevention
- Format interpolated numbers with toFixed(0) or String(Number(v)); never let Number.prototype.toString emit exponents into definitions.
- Strip units/separators from numbers before embedding them in definition strings.
- Avoid exponent, hex, and underscore numeric syntax in string definitions.
When it happens
Trigger: tokenize() (via StrParser's constructor, i.e. any string-definition parse) hits a digit-run containing exponent notation ('1e5'), leading zeros ('007'), double dots ('1.2.3'), trailing junk ('3px'), underscores ('1_000'), or a bigint spelled as '-0n'.
Common situations: Porting TypeScript type expressions like 'number >= 1e6' or '0x10' into omptype string definitions; copy-pasted config values with units ('30min'); building definitions programmatically with Number formatting that emits exponents ('1e+21' from String(1e21)).
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unexpected character '${c}' in "${src}"
- unexpected end of definition "${this.#src}"
- unsupported default literal in "${this.#src}"
- trailing tokens in definition "${this.#src}"
- expected bound after comparator in "${this.#src}"
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0499f38ec8f8f16d.
Report an issue: GitHub.