mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
Surface better error message when Claude Code process exits unexpectedly (#366)
As seen in https://github.com/zed-industries/zed/issues/39563, Claude Agent child processes can die mid-session (crash, signal, OOM, et al). When that happens, the SDK throws errors with internal messages like `"ProcessTransport closed"`, `"Failed to write to process stdin"`, or `"process terminated by signal"`. These would bubble up to the user as-is, which is not helpful. At this point, it’s [not possible to continue the session](https://github.com/zed-industries/zed/issues/39563#issuecomment-3776814727) either (which I also confirmed myself), but that is not obvious from the error the user sees (screenshot on the left). In my testing, I could not get the `Error: ProcessTransport is not ready for writing` error, but you can easily trigger the `SIGTERM` (exit code 143) by simply killing the `claude` child process spawned by the ACP adapter while the agent is streaming a response: <img width="1621" height="54" alt="image" src="https://github.com/user-attachments/assets/29d989f1-7e56-44b3-992d-065218444958" /> In this case, you’d do `kill 74573` to trigger the error. AFAICT, the child process is managed internally by the Claude Agent SDK (inside the `query` object returned by `query()`). The ACP agent only sees it as an `AsyncGenerator`. There’s no `process.pid` or `ChildProcess` handle exposed to check liveness against. The only way to discover the process is dead is when the SDK throws one of these transport-level errors*. \*I got these error strings by asking Opus 4.6 to de-obfuscate (`node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs`) | Before | After | |--------|--------| | <img width="466" height="62" alt="image" src="https://github.com/user-attachments/assets/dc959924-0929-4587-9ddd-4a3873f1fa5d" /> | <img width="462" height="77" alt="image" src="https://github.com/user-attachments/assets/77eff880-28da-489a-b9e3-e9f93abf3c7f" /> | In other words, I think the best we (the ACP adapter) can do here is to grep for these transport errors and surface a _better_ error message to the user, as seen above. --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
This commit is contained in:
@@ -711,6 +711,27 @@ export class ClaudeAcpAgent implements Agent {
|
||||
}
|
||||
}
|
||||
throw new Error("Session did not end in result");
|
||||
} catch (error) {
|
||||
if (error instanceof RequestError || !(error instanceof Error)) {
|
||||
throw error;
|
||||
}
|
||||
const message = error.message;
|
||||
if (
|
||||
message.includes("ProcessTransport") ||
|
||||
message.includes("terminated process") ||
|
||||
message.includes("process exited with") ||
|
||||
message.includes("process terminated by signal") ||
|
||||
message.includes("Failed to write to process stdin")
|
||||
) {
|
||||
this.logger.error(`Session ${params.sessionId}: Claude Agent process died: ${message}`);
|
||||
session.input.end();
|
||||
delete this.sessions[params.sessionId];
|
||||
throw RequestError.internalError(
|
||||
undefined,
|
||||
"The Claude Agent process exited unexpectedly. Please start a new session.",
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
if (!handedOff) {
|
||||
session.promptRunning = false;
|
||||
|
||||
Reference in New Issue
Block a user