{"record":{"id":"605a989aa746c73f","repo":"can1357/oh-my-pi","slug":"unexpected-response-result-op","errorCode":null,"errorMessage":"Unexpected response ${result.op}","messagePattern":"Unexpected response (.+?)","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/ps-tui.ts","lineNumber":158,"sourceCode":"\t\tthis.#ui.requestRender();\n\t}\n\n\t// -- actions ---------------------------------------------------------------\n\n\tasync #act(verb: \"stop\" | \"kill\" | \"restart\"): Promise<void> {\n\t\tconst entry = this.#flat[this.#selected];\n\t\tif (!entry) return;\n\t\tconst name = entry.row.snapshot.name;\n\t\tthis.#setStatus(chalk.yellow(`${verb} ${name}…`));\n\t\ttry {\n\t\t\tconst client = await this.#client(entry.scope);\n\t\t\tif (!client) throw new Error(\"Scope is not addressable from this machine\");\n\t\t\tconst result = await client.request(\n\t\t\t\tverb === \"restart\"\n\t\t\t\t\t? { op: \"restart\", name }\n\t\t\t\t\t: { op: \"stop\", name, timeoutMs: verb === \"kill\" ? KILL_GRACE_MS : 5_000 },\n\t\t\t);\n\t\t\tif (result.op !== \"restart\" && result.op !== \"stop\") throw new Error(`Unexpected response ${result.op}`);\n\t\t\tthis.#setStatus(\n\t\t\t\tchalk.green(\n\t\t\t\t\t`${verb === \"restart\" ? \"Restarted\" : verb === \"kill\" ? \"Killed\" : \"Stopped\"} ${daemonLabel(result.daemon)}`,\n\t\t\t\t),\n\t\t\t);\n\t\t\tvoid this.#refresh();\n\t\t} catch (error) {\n\t\t\tthis.#setStatus(\n\t\t\t\tchalk.red(`${verb} ${name} failed: ${error instanceof Error ? error.message : String(error)}`),\n\t\t\t);\n\t\t}\n\t}\n\n\tasync #openInfo(): Promise<void> {\n\t\tconst entry = this.#flat[this.#selected];\n\t\tif (!entry) return;\n\t\ttry {\n\t\t\tconst client = await this.#client(entry.scope);","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/ps-tui.ts#L140-L176","documentation":"In `#act`, after a restart/stop request is sent, the TUI checks the reply op is either \"restart\" or \"stop\" (the request is verb-dependent). If the broker returns any other op — an error envelope, a foreign message type — the action cannot be confirmed and this error is shown in the status bar. It indicates CLI/broker protocol disagreement rather than a failed daemon operation.","triggerScenarios":"Pressing s/x/r in the monitor where `client.request(...)` resolves with a response whose `op` is neither \"restart\" nor \"stop\" — e.g. an error response because the daemon vanished mid-action, or a broker running an incompatible protocol version.","commonSituations":"Killing a daemon that exits/is reaped at the same moment; a broker upgraded between table refresh and action; two omp versions installed with the older broker still owning the runtime socket.","solutions":["Retry the action after the table refreshes; if the daemon already exited the row will show a terminal state.","Restart the broker so CLI and broker share one protocol version, then retry.","Verify only one omp installation/broker owns the runtime socket; remove stale brokers."],"exampleFix":"// before\nif (result.op !== \"restart\" && result.op !== \"stop\") throw new Error(`Unexpected response ${result.op}`);\n// after\nif (result.op === \"error\") throw new Error(`Action rejected: ${result.message}`);\nif (result.op !== \"restart\" && result.op !== \"stop\") throw new Error(`Unexpected response ${result.op}`);","handlingStrategy":"type-guard","validationCode":"const listing = await client.request({ op: \"list\" });\nif (listing.op === \"list\" && !listing.daemons.some(d => d.name === name)) {\n  setStatus(`${name} is already gone`);\n  return;\n}","typeGuard":"function isActionResponse(r: { op: string }): r is { op: \"restart\" | \"stop\"; daemon: DaemonSnapshot } {\n  return r.op === \"restart\" || r.op === \"stop\";\n}","tryCatchPattern":"try {\n  const result = await client.request(request);\n  if (!isActionResponse(result)) throw new Error(`Unexpected response ${result.op}`);\n  this.#setStatus(chalk.green(`${verb} ${daemonLabel(result.daemon)}`));\n} catch (error) {\n  this.#setStatus(chalk.red(`${verb} ${name} failed: ${error instanceof Error ? error.message : String(error)}`));\n}","preventionTips":["Refresh the table before acting so terminal-state rows can't be targeted.","Treat error-op replies as first-class cases with their own status messages.","After upgrading omp, restart brokers before using TUI actions."],"tags":["ipc","protocol-mismatch","tui"],"backgroundTag":"unexpected-response-op","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}