can1357/oh-my-pi · error · OmpTypeError

unexpected end of definition "${this.#src}"

Error message

unexpected end of definition "${this.#src}"

What it means

The parser called #next() when the token stream was exhausted — the definition string ended where another token was required. Callers include t() (primary parsing), hi (right bound), limit (after == or %), and name (after #). This is the 'premature end of input' error for the string-definition mini-grammar.

Source

Thrown at packages/omptype/src/ir.ts:352

class StrParser {
	#toks: Tok[];
	#pos = 0;
	#src: string;
	#resolve: AliasResolver | undefined;

	constructor(src: string, resolve?: AliasResolver) {
		this.#src = src;
		this.#resolve = resolve;
		this.#toks = tokenize(src);
	}

	#peek(offset = 0): Tok | undefined {
		return this.#toks[this.#pos + offset];
	}

	#next(): Tok {
		const t = this.#toks[this.#pos++];
		if (!t) throw new OmpTypeError(`unexpected end of definition "${this.#src}"`);
		return t;
	}

	#eatOp(v: string): boolean {
		const t = this.#peek();
		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("=")) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Append the missing token: a limit after a comparator ('number>=1'), an operand after '|' or '&', a ')' for '(', or an identifier after '#'.
  2. If the definition is interpolated, verify every interpolated value is defined and non-empty before building the string.
  3. Log/echo the full definition string (included in the message) and compare against expected syntax to spot truncation.
  4. Prefer composing from validated parts or use the object/IR form of the schema instead of string concatenation.

Example fix

// before
schema.parse("number>=");
// after
schema.parse("number>=1");
Defensive patterns

Strategy: validation

Validate before calling

function assertComplete(def) {
  if (/[<>=|&%(#%]$/.test(def.trim())) throw new Error(`definition ends mid-construct: ${def}`);
}

Try / catch

try {
  const schema = parse(def);
} catch (e) {
  if (String(e.message).includes("unexpected end of definition")) {
    // log def and its length; check the interpolation that built it
  }
  throw e;
}

Prevention

When it happens

Trigger: Definitions that stop mid-construct: 'string<' (generic without args), 'number>=' (bound without a limit), '5 %' (divisor missing), 'array#' (brand name missing), '(' (unclosed group reaching EOF), 'string|' (dangling union bar).

Common situations: Truncated strings from template concatenation (`number >= ${}` with undefined min printing as nothing is caught earlier, but a trailing operator is common); hand-edited schemas where a value was deleted; string slicing that chopped the tail off a definition.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/3ee8dc850b40b871. Report an issue: GitHub.