can1357/oh-my-pi · error

Unknown daemon operation: ${op}

Error message

Unknown daemon operation: ${op}

What it means

parseDaemonOperation dispatches on the operation name and throws for any op not in its switch table. This is the protocol's exhaustiveness guard: the broker only implements a fixed set of daemon operations.

Source

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

		}
		case "send":
			return {
				op,
				name: stringValue(source.name, "operation.name"),
				data: optionalString(source.data, "operation.data"),
				signal: source.signal === undefined ? undefined : daemonSignal(source.signal),
			};
		case "stop":
			return {
				op,
				name: stringValue(source.name, "operation.name"),
				timeoutMs: numberValue(source.timeoutMs, "operation.timeoutMs"),
			};
		case "restart":
		case "describe":
			return { op, name: stringValue(source.name, "operation.name") };
		default:
			throw new Error(`Unknown daemon operation: ${op}`);
	}
}

/** Decode a broker result using its pending operation as the discriminator. */
export function parseDaemonRpcResult(operation: DaemonOperation, value: unknown): DaemonRpcResult {
	const source = record(value, `${operation.op} result`);
	switch (operation.op) {
		case "ping":
			return { op: "ping", projectDir: stringValue(source.projectDir, "result.projectDir") };
		case "start":
			return {
				op: "start",
				daemon: parseDaemonSnapshot(source.daemon),
				readyTimedOut: booleanValue(source.readyTimedOut, "result.readyTimedOut"),
			};
		case "list": {
			if (!Array.isArray(source.daemons)) throw new Error("result.daemons must be an array");
			return { op: "list", daemons: source.daemons.map(parseDaemonSnapshot) };

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a supported operation name; consult parseDaemonOperation in packages/coding-agent/src/launch/protocol.ts for the exact set.
  2. Restart/upgrade the daemon so versions match the client.
  3. Log the `op` value from the rejected request to spot typos.
  4. If the op is genuinely new, add a case to parseDaemonOperation and a matching parseDaemonRpcResult branch.

Example fix

// before
await broker.request({ op: "status", name: "main" });
// after
await broker.request({ op: "describe", name: "main" });
Defensive patterns

Strategy: type-guard

Validate before calling

const KNOWN_OPS = ["start", "stop", "restart", "list", "logs", "wait", "describe"] as const;
type Op = typeof KNOWN_OPS[number];
function assertOp(op: string): asserts op is Op {
  if (!KNOWN_OPS.includes(op as Op)) throw new Error(`unsupported daemon op: ${op}`);
}

Type guard

const isKnownOp = (op: string): op is "start" | "stop" | "restart" | "list" | "logs" | "wait" | "describe" =>
  ["start", "stop", "restart", "list", "logs", "wait", "describe"].includes(op);

Try / catch

try {
  await broker.request(req);
} catch (err) {
  if (err.message.startsWith("Unknown daemon operation")) {
    logger.error("client/daemon protocol mismatch", { op: req.op });
  }
  throw err;
}

Prevention

When it happens

Trigger: Sending a request whose `op` string is misspelled, unknown to this version, or invented (e.g. "status" when only start/stop/restart/list/logs/wait/describe exist).

Common situations: Client and daemon version mismatch (newer client sends an op the older daemon doesn't know), typos in hand-crafted RPC scripts, or third-party tooling speaking a divergent protocol dialect.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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