can1357/oh-my-pi · error · OmpTypeError

invalid regular expression "${src.slice(i, end)}"

Error message

invalid regular expression "${src.slice(i, end)}"

What it means

A properly delimited regex literal `/.../flags` was tokenized, but `new RegExp(source, flags)` threw — the pattern or its flags are syntactically invalid JavaScript. The tokenizer rethrows as `OmpTypeError` including the literal text.

Source

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

			toks.push({ t: "str", v: value });
			i = j + 1;
			continue;
		}
		if (c === "/") {
			let j = i + 1;
			for (; j < n; j++) {
				if (src[j] === "\\") j++;
				else if (src[j] === "/") break;
			}
			if (j >= n) throw new OmpTypeError(`unterminated regular expression in "${src}"`);
			let end = j + 1;
			while (end < n && /[dgimsuvy]/.test(src[end])) end++;
			const source = src.slice(i + 1, j);
			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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Test the pattern with `new RegExp(p, flags)` in a REPL to see the underlying SyntaxError.
  2. Remove invalid/duplicate flags; valid flags are d,g,i,m,s,u,v,y.
  3. Replace engine-unsupported constructs (e.g. `(?R)`, `\K`) with JS-compatible equivalents.
  4. Pre-validate the regex with a try/catch around `new RegExp` before embedding it in the expression.

Example fix

// before
type(`value ~= /[a-z+/`); // unbalanced class
// after
type(`value ~= /[a-z]+/`);
Defensive patterns

Strategy: validation

Validate before calling

function assertValidRegex(pattern: string, flags: string): void {
  try { new RegExp(pattern, flags); } catch (e) {
    throw new Error(`Invalid regex /${pattern}/${flags}: ${(e as Error).message}`);
  }
}

Try / catch

try {
  const t = new TypeExpression(src);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("invalid regular expression")) {
    throw new Error(`Fix pattern syntax: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Malformed patterns like `/(/` (unclosed group), `/[a-/`, `/(?<name/x)/` (invalid group), or invalid flag combos like `/x/yy` (duplicate flag).

Common situations: Regexes authored for another flavor (PCRE/RE2 constructs like lookbehind variants unsupported by the JS engine version); duplicated or typo'd flags; hand-edited patterns with unbalanced brackets.

Related errors


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