{"record":{"id":"5663c0301a5bdc34","repo":"can1357/oh-my-pi","slug":"rpc-command-failed","errorCode":null,"errorMessage":"RPC command failed","messagePattern":"RPC command failed","errorType":"exception","errorClass":"RpcCommandError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/rpc/rpc-client.ts","lineNumber":1245,"sourceCode":"\t): void {\n\t\tif (!this.#process?.stdin) {\n\t\t\tthrow new Error(\"Client not started\");\n\t\t}\n\t\tconst stdin = this.#process.stdin;\n\t\tstdin.write(`${JSON.stringify(frame)}\\n`);\n\t\tif (!(\"flush\" in stdin)) return;\n\t\tconst flushResult = (stdin as FileSink).flush();\n\t\tif (isPromise(flushResult)) {\n\t\t\tflushResult.catch((err: Error) => {\n\t\t\t\tonError?.(err);\n\t\t\t});\n\t\t}\n\t}\n\n\t#getData<T>(response: RpcResponse): T {\n\t\tif (!response.success) {\n\t\t\tconst errorResponse = response as Extract<RpcResponse, { success: false }>;\n\t\t\tthrow new RpcCommandError(errorResponse.error, errorResponse.command, errorResponse.code);\n\t\t}\n\t\t// Type assertion: we trust response.data matches T based on the command sent.\n\t\t// This is safe because each public method specifies the correct T for its command.\n\t\tconst successResponse = response as Extract<RpcResponse, { success: true; data: unknown }>;\n\t\treturn successResponse.data as T;\n\t}\n}\n","sourceCodeStart":1227,"sourceCodeEnd":1253,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/rpc/rpc-client.ts#L1227-L1253","documentation":"#getData() unwraps a successful RpcResponse; when the response carries success:false it throws RpcCommandError carrying the server's error message, the command name, and an optional machine-readable code. This is the transport for every server-side command failure (invalid command, session errors, internal server exceptions).","triggerScenarios":"Any command sent via #send whose RpcResponse comes back success:false — e.g. get_messages on an unknown session, an unsupported command, or the server throwing while handling a request.","commonSituations":"Calling a command the child binary doesn't support (version skew); referencing a session/prompt that doesn't exist; server-side validation or internal errors; sending commands to a busy or closing server.","solutions":["Read error.command and error.code on the RpcCommandError to pinpoint which command failed and why.","Catch RpcCommandError specifically rather than generic Error.","Align client and server versions so the command exists.","Fix the parameters passed to the failing command per the server's error message."],"exampleFix":"// before\nconst msgs = await client.getMessages(); // throws generic Error\n// after\ntry {\n  const msgs = await client.getMessages();\n} catch (err) {\n  if (err instanceof RpcCommandError && err.command === \"get_messages\") {\n    // handle per err.code\n  } else throw err;\n}","handlingStrategy":"try-catch","validationCode":"if (!supportedCommands.has(command.type)) throw new Error(`unsupported command: ${command.type}`);","typeGuard":"function isRpcCommandError(e: unknown): e is RpcCommandError {\n  return e instanceof RpcCommandError;\n}","tryCatchPattern":"try {\n  const data = await client.getMessages();\n} catch (e) {\n  if (isRpcCommandError(e)) {\n    switch (e.code) {\n      case \"SESSION_NOT_FOUND\": return fallbackToEmptyHistory();\n      default: throw e;\n    }\n  }\n  throw e;\n}","preventionTips":["Catch RpcCommandError, not bare Error, around RPC calls.","Version-align client and server so all commands exist.","Log err.command and err.code for diagnosis.","Validate command arguments against the server's expectations."],"tags":["rpc","command-error","server-error","ipc"],"backgroundTag":"rpc-command-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}