Note: This report was investigated with the assistance of Claude (Anthropic's AI coding assistant) — it reproduced the crash, performed the bisect below, and traced the root cause to the linked upstream PR, all verified by me before filing. Flagging this upfront per the "(for AI issues)" convention on this tracker.
Reproduction steps
- Have a workspace with an ACP thread open, backed by an external agent server (in my repro, an ACP-bridged agent talking to a local LM Studio instance).
- Launch Zed (
cargo run --bin zed, debug build) so the workspace/session restores that thread.
- Within roughly 60–150 seconds of launch, Zed crashes.
- Relaunching reproduces the same crash again (crash loop), since the same thread state gets restored.
This reproduces from a clean checkout of main with no local modifications — no custom settings or extensions needed beyond having that ACP thread persisted.
Zed version and system specs
Zed: v1.14.0 (dev build, cargo run --bin zed)
OS: macOS 26.5.2 (build 25F84)
Architecture: aarch64
Reproduced directly against main at 82aef44308 ("gpui: Add an abstraction for scheduling foreground work for idle periods, and implement it for the web (#61827)") — with agent-client-protocol pinned to 2.0.0 per Cargo.lock at that commit.
Attach Zed log file
Nothing relevant was written to Zed.log — the crash happens below the level the app's own logger can catch (it's an illegal-instruction trap on a background dispatch worker thread, not a Rust panic). The macOS crash reporter's .ips diagnostic report is what actually captured it; the relevant parts are transcribed below.
Crash signature
EXCEPTION: EXC_BAD_ACCESS (SIGILL), subtype KERN_PROTECTION_FAILURE
message: "Could not determine thread index for stack guard region"
This message is emitted when Rust's stack-overflow guard-page handler can't identify the overflowing thread, which happens on GCD worker threads (_dispatch_worker_thread2 → pthread_wqthread) — these have a much smaller stack than the main thread.
The faulting thread's top frames are all inside agent_client_protocol::jsonrpc::handlers, with ChainedHandler<ChainedHandler<ChainedHandler<...>>> repeated many times while dispatching a RequestPermissionRequest:
agent_client_protocol::jsonrpc::handlers::RequestHandler::handle_dispatch_from (RequestPermissionRequest)
agent_client_protocol::role::handle_incoming_dispatch
agent_client_protocol::jsonrpc::handlers::RequestHandler::handle_dispatch_from
agent_client_protocol::jsonrpc::handlers::ChainedHandler::handle_dispatch_from
agent_client_protocol::jsonrpc::handlers::ChainedHandler::handle_dispatch_from
agent_client_protocol::jsonrpc::handlers::ChainedHandler::handle_dispatch_from
... (repeats several more times)
I reproduced this three separate times with the identical signature (only the guard-page address differs between runs).
Bisect
I bisected against the agent-client-protocol dependency's version history in Cargo.lock rather than a blind commit range, since the crash is entirely inside that crate:
| Commit |
agent-client-protocol |
Result |
d1548bd013 ("repl: Show add-cell controls in empty notebooks", #61329) |
1.3.0 |
Ran cleanly for 4+ minutes with the same workspace state, no crash |
984e3bd0ce ("acp: Update agent-client-protocol SDK to 2.0.0", #61570) |
2.0.0 |
Crashed within ~90 seconds, identical signature |
Both were verified directly (checked out, built, and run) rather than inferred from the log alone.
Root cause (best guess)
ChainedHandler<H1, H2> in agent-client-protocol 2.0.0 (src/jsonrpc/handlers.rs) is:
pub struct ChainedHandler<H1, H2> {
handler1: H1,
handler2: H2,
}
impl<Counterpart: Role, H1, H2> HandleDispatchFrom<Counterpart> for ChainedHandler<H1, H2>
where
H1: HandleDispatchFrom<Counterpart>,
H2: HandleDispatchFrom<Counterpart>,
{
async fn handle_dispatch_from(&mut self, message: Dispatch, connection: ConnectionTo<Counterpart>) -> Result<Handled<Dispatch>, crate::Error> {
match self.handler1.handle_dispatch_from(message, connection.clone()).await? {
Handled::Yes => Ok(Handled::Yes),
Handled::No { message, retry: retry1 } => match self.handler2.handle_dispatch_from(message, connection).await? {
// ...
}
}
}
}
Nothing here boxes or type-erases H1/H2. Zed's crates/agent_servers/src/acp.rs registers 9 handlers via on_receive_request!(), so the compiler builds a ChainedHandler<ChainedHandler<ChainedHandler<...H9>>> where each nesting level's generated async fn state machine embeds the entire next level's state inline. In an unoptimized (dev) build this produces an enormous unboxed future, and dispatching a request on a worker thread with a smaller stack overflows it. This looks like the same class of bug Zed has hit (and fixed) elsewhere with unbounded/oversized stack usage — e.g. #58325, #51637, #41397, #35813 — usually addressed with stacker-style dynamic stack growth or by boxing the chain.
This was introduced upstream by agentclientprotocol/rust-sdk PR #277 ("refactor(acp)!: clarify routing and handler APIs", part of the 2.0.0 release) and pulled into Zed via #61570. I couldn't find an existing issue or PR addressing it in either repo.
Relevant Zed settings
An ACP-bridged external agent server configured against a local LM Studio instance was open in the restored workspace when this reproduced.
(for AI issues) Model provider details
External agent via Agent Client Protocol (ACP), bridging to a local LM Studio instance.
Reproduction steps
cargo run --bin zed, debug build) so the workspace/session restores that thread.This reproduces from a clean checkout of
mainwith no local modifications — no custom settings or extensions needed beyond having that ACP thread persisted.Zed version and system specs
Reproduced directly against
mainat82aef44308("gpui: Add an abstraction for scheduling foreground work for idle periods, and implement it for the web (#61827)") — withagent-client-protocolpinned to 2.0.0 perCargo.lockat that commit.Attach Zed log file
Nothing relevant was written to
Zed.log— the crash happens below the level the app's own logger can catch (it's an illegal-instruction trap on a background dispatch worker thread, not a Rust panic). The macOS crash reporter's.ipsdiagnostic report is what actually captured it; the relevant parts are transcribed below.Crash signature
This message is emitted when Rust's stack-overflow guard-page handler can't identify the overflowing thread, which happens on GCD worker threads (
_dispatch_worker_thread2→pthread_wqthread) — these have a much smaller stack than the main thread.The faulting thread's top frames are all inside
agent_client_protocol::jsonrpc::handlers, withChainedHandler<ChainedHandler<ChainedHandler<...>>>repeated many times while dispatching aRequestPermissionRequest:I reproduced this three separate times with the identical signature (only the guard-page address differs between runs).
Bisect
I bisected against the
agent-client-protocoldependency's version history inCargo.lockrather than a blind commit range, since the crash is entirely inside that crate:agent-client-protocold1548bd013("repl: Show add-cell controls in empty notebooks", #61329)984e3bd0ce("acp: Update agent-client-protocol SDK to 2.0.0", #61570)Both were verified directly (checked out, built, and run) rather than inferred from the log alone.
Root cause (best guess)
ChainedHandler<H1, H2>inagent-client-protocol2.0.0 (src/jsonrpc/handlers.rs) is:Nothing here boxes or type-erases
H1/H2. Zed'scrates/agent_servers/src/acp.rsregisters 9 handlers viaon_receive_request!(), so the compiler builds aChainedHandler<ChainedHandler<ChainedHandler<...H9>>>where each nesting level's generatedasync fnstate machine embeds the entire next level's state inline. In an unoptimized (dev) build this produces an enormous unboxed future, and dispatching a request on a worker thread with a smaller stack overflows it. This looks like the same class of bug Zed has hit (and fixed) elsewhere with unbounded/oversized stack usage — e.g. #58325, #51637, #41397, #35813 — usually addressed withstacker-style dynamic stack growth or by boxing the chain.This was introduced upstream by
agentclientprotocol/rust-sdkPR #277 ("refactor(acp)!: clarify routing and handler APIs", part of the 2.0.0 release) and pulled into Zed via #61570. I couldn't find an existing issue or PR addressing it in either repo.Relevant Zed settings
An ACP-bridged external agent server configured against a local LM Studio instance was open in the restored workspace when this reproduced.
(for AI issues) Model provider details
External agent via Agent Client Protocol (ACP), bridging to a local LM Studio instance.