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:
Kunall Banerjee
2026-03-03 07:54:51 -05:00
committed by GitHub
parent b4f56b17fc
commit c0e2cee265

View File

@@ -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;