can1357/oh-my-pi · error · OmpTypeError
unsupported default literal in "${this.#src}"
Error message
unsupported default literal in "${this.#src}" What it means
After a '= default' marker, parseTop only accepts literal tokens (num, bigint, date, str) or the identifiers true/false/null/undefined. Any other token (a keyword like 'string', an identifier, an operator) is rejected because defaults must be compile-time literals, not computed expressions or type references.
Source
Thrown at packages/omptype/src/ir.ts:376
if (t?.t === "op" && t.v === v) {
this.#pos++;
return true;
}
return false;
}
/** Full definition with optional trailing `= literal` default and/or `?` optional marker. */
parseTop(): ParsedTop {
const ir = this.parseUnion();
let def: unknown;
let hasDefault = false;
if (this.#eatOp("=")) {
const t = this.#next();
if (t.t === "num" || t.t === "bigint" || t.t === "date" || t.t === "str") def = t.v;
else if (t.t === "id" && (t.v === "true" || t.v === "false")) def = t.v === "true";
else if (t.t === "id" && t.v === "null") def = null;
else if (t.t === "id" && t.v === "undefined") def = undefined;
else throw new OmpTypeError(`unsupported default literal in "${this.#src}"`);
hasDefault = true;
}
const optional = this.#eatOp("?");
this.#expectEnd();
return { ir, def, hasDefault, optional };
}
#expectEnd(): void {
if (this.#pos < this.#toks.length) {
throw new OmpTypeError(`trailing tokens in definition "${this.#src}"`);
}
}
parseUnion(): IR {
const first = this.parseIntersection();
if (!this.#eatOp("|")) return first;
const members = [first, this.parseIntersection()];
while (this.#eatOp("|")) members.push(this.parseIntersection());View on GitHub (pinned to 9690622007)
Solutions
- Quote string defaults: "string='abc'" not 'string=abc'.
- Use only literal forms after '=': numbers, 5n-style bigints, dates, quoted strings, true/false/null/undefined.
- Compute the value in code and supply it through the API's runtime-default mechanism if a non-literal default is needed.
- Check ordering: the '=' clause follows the whole union, so ensure the default token itself is a literal, not an expression.
Example fix
// before
schema.parse("string=hello");
// after
schema.parse("string='hello'"); Defensive patterns
Strategy: validation
Validate before calling
function isValidDefault(d) {
return typeof d === "number" || typeof d === "bigint" || d instanceof Date ||
typeof d === "string" || typeof d === "boolean" || d === null || d === undefined;
} Type guard
function isLiteralDefault(v) {
return v === null || v === undefined || typeof v === "boolean" ||
typeof v === "number" || typeof v === "bigint" || typeof v === "string" || v instanceof Date;
} Try / catch
try {
const schema = parse(def);
} catch (e) {
if (String(e.message).includes("unsupported default literal")) {
// quote string defaults or supply the default via the runtime API
}
throw e;
} Prevention
- Always quote string defaults: "string='abc'".
- Remember the allowed default forms: num, bigint, date, quoted string, true/false/null/undefined.
- Pass non-literal defaults through the API's value-based mechanism, not the string grammar.
When it happens
Trigger: Definitions like 'string=hello' (unquoted string), 'number=Math.PI', "string='a' | 'b'=..." with a non-literal after '=', or 'boolean=yes'.
Common situations: Writing defaults for string types without quotes ('string=abc' instead of "string='abc'"); referencing constants by name expecting runtime evaluation; pasting TS default-value syntax ('number = 5' with spaces is fine, but 'number=default' is not).
Related errors
- Malformed number literal '${raw}'
- unexpected character '${c}' in "${src}"
- unexpected end of definition "${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/a382539119537860.
Report an issue: GitHub.