can1357/oh-my-pi · error · ToolError

ready requires log or port

Error message

ready requires log or port

What it means

A `ready` condition must give the tool some way to detect readiness — either a log substring (`ready.log`) or a port (`ready.port`). commandSpec() throws this ToolError when `ready` is provided but both fields are absent/empty, making the readiness condition undetectable.

Source

Thrown at packages/coding-agent/src/tools/hub/launch.ts:190

function requiredName(params: LaunchParams): string {
	if (!params.name) throw new ToolError(`${params.op} requires name`);
	return params.name;
}

function timeoutMs(value: number | undefined, fallbackSeconds: number): number {
	const seconds = Math.max(0.05, Math.min(3_600, value ?? fallbackSeconds));
	return Math.round(seconds * 1_000);
}

function commandSpec(params: LaunchParams, session: ToolSession): DaemonSpec {
	const name = requiredName(params);
	if (!params.application) throw new ToolError("start requires application");
	const ready = params.ready;
	const detached = params.detached ?? false;
	if (ready?.port !== undefined && (!Number.isInteger(ready.port) || ready.port < 1 || ready.port > 65_535)) {
		throw new ToolError("ready.port must be an integer from 1 to 65535");
	}
	if (ready && !ready.log && ready.port === undefined) throw new ToolError("ready requires log or port");
	return {
		name,
		application: params.application,
		args: params.args ?? [],
		env: params.env ?? {},
		cwd: resolveToCwd(params.cwd ?? session.cwd, session.cwd),
		pty: detached ? false : (params.pty ?? true),
		ready: ready
			? {
					log: ready.log,
					port: ready.port,
					host: ready.host,
					timeoutMs: timeoutMs(ready.timeout, 30),
				}
			: undefined,
		restart: params.restart ?? "no",
		persist: (params.persist ?? false) || detached,
		detached,

View on GitHub (pinned to 9690622007)

Solutions

  1. Add a detection source: ready: { log: "listening on" } or ready: { port: 3000 }.
  2. If no readiness signal is needed, omit the `ready` parameter entirely instead of passing an empty object.
  3. Combine both (log + port) if you want a stronger readiness check.

Example fix

// before
launch({ op: "start", name: "api", application: "bun", ready: {} })
// throws: ready requires log or port

// after
launch({ op: "start", name: "api", application: "bun", ready: { log: "Listening" } })
Defensive patterns

Strategy: validation

Validate before calling

if (params.ready && !params.ready.log && params.ready.port === undefined) {
  throw new Error("ready requires log or port");
}

Try / catch

try {
  await launchTool.run({ op: "start", name, application, ready });
} catch (err) {
  if (err instanceof ToolError && err.message === "ready requires log or port") {
    // add ready.log or ready.port, or drop ready entirely
  } else throw err;
}

Prevention

When it happens

Trigger: launch({ op: "start", name, application, ready: {} }) or ready: { } after JSON filtering removed empty log/port values.

Common situations: Model emitted an empty ready object as a placeholder; caller intended to wait unconditionally and added ready with no fields; serialization dropped falsy values leaving an empty ready.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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