From c0e2cee265984d64b04884ecdaa5a9a13591b5f6 Mon Sep 17 00:00:00 2001 From: Kunall Banerjee Date: Tue, 3 Mar 2026 07:54:51 -0500 Subject: [PATCH] Surface better error message when Claude Code process exits unexpectedly (#366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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: image 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 | |--------|--------| | image | image | 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 --- src/acp-agent.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/acp-agent.ts b/src/acp-agent.ts index 676ef36b..8d7436ab 100644 --- a/src/acp-agent.ts +++ b/src/acp-agent.ts @@ -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;