can1357/oh-my-pi · error

Invalid readiness regex: ${error instanceof Error ? error.me

Error message

Invalid readiness regex: ${error instanceof Error ? error.message : String(error)}

What it means

DaemonBroker.start validates spec.ready.log by compiling it with new RegExp(pattern, "u") before launching the daemon. If the pattern is syntactically invalid (or uses features incompatible with the 'u' flag), the launch is aborted with this message so the failure surfaces before a process is spawned. The underlying RegExp syntax error message is appended.

Source

Thrown at packages/coding-agent/src/launch/broker.ts:628

		if (this.#startingNames.has(spec.name)) {
			throw new Error(`Daemon ${spec.name} is already starting`);
		}
		this.#startingNames.add(spec.name);
		let record: ManagedDaemon;
		try {
			const existing = this.#records.get(spec.name);
			if (existing) await this.#refreshDetached(existing);
			if (existing && !terminalState(existing.snapshot.state)) {
				throw new Error(`Daemon ${spec.name} is already ${existing.snapshot.state}`);
			}
			if (existing && existing.pendingCompletions.length > 0) {
				throw new Error(`Daemon ${spec.name} has unacknowledged completion notifications`);
			}
			if (spec.ready?.log) {
				try {
					new RegExp(spec.ready.log, "u");
				} catch (error) {
					throw new Error(`Invalid readiness regex: ${error instanceof Error ? error.message : String(error)}`);
				}
			}
			const stat = await fs.stat(spec.cwd);
			if (!stat.isDirectory()) throw new Error(`Daemon cwd is not a directory: ${spec.cwd}`);
			const dir = path.join(this.#runtimeDir, "daemons", spec.name);
			const now = Date.now();
			record = {
				spec,
				snapshot: {
					name: spec.name,
					id: crypto.randomUUID(),
					state: "starting",
					createdAt: now,
					startedAt: now,
					restartCount: 0,
					outputBytes: 0,
					owner,
					persist: spec.persist,

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix the ready.log pattern so it compiles under the 'u' flag; test with `new RegExp(pattern, "u")` locally.
  2. Escape special characters properly (in JSON config, double the backslashes: "\\d+").
  3. Remove ready.log entirely if log-based readiness detection is not needed.

Example fix

// before
ready: { log: "listening on (port \d+" }
// after
ready: { log: "listening on \\(port \\d+" }  // compiles under new RegExp(p, "u")
Defensive patterns

Strategy: validation

Validate before calling

if (spec.ready?.log) {
  try { new RegExp(spec.ready.log, "u"); }
  catch (e) { throw new Error(`Bad ready.log in spec '${spec.name}': ${e.message}`); }
}

Type guard

function isValidRegexU(p: unknown): p is string {
  if (typeof p !== "string") return false;
  try { new RegExp(p, "u"); return true; } catch { return false; }
}

Try / catch

try {
  await broker.start(spec);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Invalid readiness regex:")) {
    // fix or drop spec.ready.log, then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a daemon spec whose ready.log string is not a valid regular expression — e.g. unescaped '(' or '[', dangling quantifier like '++', or a lone surrogate that the 'u' flag rejects.

Common situations: Hand-written readiness patterns in config files/JSON where backslashes were not escaped (\d becomes d), or patterns copied from PCRE with syntax V8's 'u' mode rejects (e.g. invalid unicode escapes).

Related errors


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