can1357/oh-my-pi · error · Error

Unexpected broker response ${first.op}

Error message

Unexpected broker response ${first.op}

What it means

`omp ps logs` issues an initial `{op:"logs"}` request and requires a logs-shaped reply to read `first.text` / `first.terminalRows` / `first.state`. This guard throws when the broker answers with any other op, so the log payload is absent and printing would read undefined fields.

Source

Thrown at packages/coding-agent/src/cli/ps-cli.ts:229

	if (cmd.flags.json) console.log(JSON.stringify(daemon, null, 2));
	else console.log(`${verb} ${daemonLabel(daemon)}`);
}

async function runLogs(cmd: PsCommandArgs, client: DaemonBrokerClient, name: string): Promise<void> {
	const lines = Math.max(1, Math.min(1_000, Math.floor(cmd.flags.lines ?? 100)));
	// Follow mode reads the full 1000-line window on every request so overlap
	// trimming sees a stable, sliding tail; the initial print is cut to `lines`.
	const first = await client.request({
		op: "logs",
		name,
		lines: cmd.flags.follow ? 1_000 : lines,
		head: cmd.flags.head,
		grep: cmd.flags.grep,
		follow: false,
		renderTerminalRows: !cmd.flags.follow,
		timeoutMs: 30_000,
	});
	if (first.op !== "logs") throw new Error(`Unexpected broker response ${first.op}`);
	if (!cmd.flags.follow) {
		const text = first.terminalRows !== undefined ? first.terminalRows.join("\n") : first.text.replace(/\n$/, "");
		if (text) console.log(text);
		console.log(chalk.dim(`[${name}: ${first.state}]`));
		return;
	}
	const initial = first.text.replace(/\n$/, "").split("\n").slice(-lines).join("\n");
	if (initial) process.stdout.write(`${initial}\n`);
	let previous = first.text;
	let cursor = first.cursor;
	let state = first.state;
	while (!TERMINAL_STATES[state]) {
		const next = await client.request({
			op: "logs",
			name,
			lines: 1_000,
			head: false,
			grep: cmd.flags.grep,

View on GitHub (pinned to 9690622007)

Solutions

  1. Point the command at the right scope: pass `--dir <project>` or `--global <service>` matching where the daemon runs, and use the exact name from `omp ps --all`.
  2. Restart/reconnect the broker so CLI and broker protocol versions match.
  3. If the daemon has exited, check whether its metadata still exists (`<runtimeDir>/daemons/<name>/meta.json`) or view persisted logs directly from that directory.

Example fix

// before
const first = await client.request({ op: "logs", ... });
if (first.op !== "logs") throw new Error(`Unexpected broker response ${first.op}`);
// after
const first = await client.request({ op: "logs", ... });
if (first.op === "error") throw new Error(`Cannot read logs: ${first.message}`);
if (first.op !== "logs") throw new Error(`Unexpected broker response ${first.op}`);
Defensive patterns

Strategy: type-guard

Validate before calling

const listing = await client.request({ op: "list" });
if (listing.op === "list" && !listing.daemons.some(d => d.name === name)) {
  throw new Error(`No daemon "${name}" in this scope; check --dir/--global`);
}

Type guard

function isLogsResponse(r: { op: string }): r is { op: "logs"; text: string; terminalRows?: string[]; state: string; cursor?: string } {
  return r.op === "logs";
}

Try / catch

try {
  const first = await client.request({ op: "logs", name, follow: false, timeoutMs: 30_000 });
  if (!isLogsResponse(first)) throw new Error(`Unexpected broker response ${first.op}`);
} catch (err) {
  console.error(chalk.red(err instanceof Error ? err.message : String(err)));
  process.exitCode = 1;
}

Prevention

When it happens

Trigger: `runLogs` where the first `client.request({op:"logs", ..., follow:false})` resolves with a response whose `op` is not "logs" — e.g. an error/not-found response, or a broker running an incompatible protocol version.

Common situations: Fetching logs for a daemon that the connected broker doesn't own (wrong `--dir`/`--global` scope so the name resolves differently); stale broker after an omp upgrade; the daemon exited and was pruned so the broker replies with an error op.

Related errors


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