can1357/oh-my-pi · error

ready requires log or port

Error message

ready requires log or port

What it means

Thrown by readySpec() when a daemon spec's ready section defines a timeout (required) but neither a log pattern nor a port. Readiness detection works by matching log output or probing a port; a ready clause with neither would never complete, so the parser rejects it up front.

Source

Thrown at packages/coding-agent/src/launch/protocol.ts:241

}

function readyPendingList(value: unknown): ("log" | "port")[] {
	if (!Array.isArray(value)) throw new Error("daemon.readyPending must be an array");
	const result: ("log" | "port")[] = [];
	for (const item of value) {
		if (item !== "log" && item !== "port") throw new Error(`Unknown readiness condition: ${String(item)}`);
		result.push(item);
	}
	return result;
}

function readySpec(value: unknown): DaemonReadySpec {
	const source = record(value, "ready");
	const log = optionalString(source.log, "ready.log");
	const port = optionalNumber(source.port, "ready.port");
	const host = optionalString(source.host, "ready.host");
	const timeoutMs = numberValue(source.timeoutMs, "ready.timeoutMs");
	if (!log && port === undefined) throw new Error("ready requires log or port");
	return { log, port, host, timeoutMs };
}

/** Decode and validate a daemon launch specification. */
export function parseDaemonSpec(value: unknown): DaemonSpec {
	const source = record(value, "daemon spec");
	const detached = source.detached === undefined ? false : booleanValue(source.detached, "spec.detached");
	return {
		name: stringValue(source.name, "spec.name"),
		application: stringValue(source.application, "spec.application"),
		args: stringArray(source.args, "spec.args"),
		env: stringRecord(source.env, "spec.env"),
		cwd: stringValue(source.cwd, "spec.cwd"),
		pty: booleanValue(source.pty, "spec.pty"),
		ready: source.ready === undefined ? undefined : readySpec(source.ready),
		restart: restartPolicy(source.restart),
		persist: booleanValue(source.persist, "spec.persist") || detached,
		detached,

View on GitHub (pinned to 9690622007)

Solutions

  1. Add either a log pattern (ready.log) or a port (ready.port) to the ready section
  2. Remove the ready section entirely if no readiness check is needed
  3. If the log pattern became empty, restore it or switch to a port probe
  4. Keep timeoutMs present and finite — it is mandatory in this section

Example fix

// before
parseDaemonSpec({ id: "d1", command: ["srv"], ready: { timeoutMs: 5000 } })
// after
parseDaemonSpec({ id: "d1", command: ["srv"], ready: { port: 8080, timeoutMs: 5000 } })
Defensive patterns

Strategy: validation

Validate before calling

interface ReadyInput { log?: string; port?: number; host?: string; timeoutMs: number }
function hasReadyTarget(r: ReadyInput): boolean {
  return Boolean(r.log) || typeof r.port === "number";
}
if (!hasReadyTarget(ready)) throw new Error("ready requires log or port");

Type guard

function hasReadyTarget(r: { log?: string; port?: number }): boolean { return Boolean(r.log) || typeof r.port === "number"; }

Try / catch

try {
  const spec = parseDaemonSpec(raw);
} catch (err) {
  if (err instanceof Error && err.message === "ready requires log or port") {
    // drop the ready section or add a log/port condition before retrying
  } else throw err;
}

Prevention

When it happens

Trigger: parseDaemonSpec receiving ready: { timeoutMs: 5000 } with no log and no port; ready: { host: "localhost", timeoutMs: 5000 } (host alone doesn't count); log present but empty string "" combined with no port (empty string is falsy).

Common situations: Config where the log pattern was deleted or renamed during editing; setting only host/timeout and expecting defaults; empty-string log values that pass type checks but fail the presence check.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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