warpdotdev/warp · warning · anyhow::Error
Agent driver dropped while sending /exit
Error message
Agent driver dropped while sending /exit
What it means
Returned by the Claude Code harness exit() when ModelSpawner::spawn(...).await fails — the join/spawn channel dropped because the AgentDriver model it targets was released before the spawned update could run. It is an internal lifecycle race at shutdown, not a CLI failure: the /exit text never reached the terminal driver.
Source
Thrown at app/src/ai/agent_sdk/driver/harness/claude_code.rs:518
setup_events
.post_timeline_event(OzRunTimelineEvent::AgentStarted)
.await;
Ok(command_handle)
}
async fn exit(&self, foreground: &ModelSpawner<AgentDriver>) -> Result<()> {
log::info!("Sending /exit to Claude Code CLI");
let terminal_driver = self.terminal_driver.clone();
foreground
.spawn(move |_, ctx| {
terminal_driver.update(ctx, |driver, ctx| {
driver.send_text_to_cli(CLAUDE_EXIT_COMMAND.to_string(), ctx);
});
})
.await
.map_err(|_| anyhow::anyhow!("Agent driver dropped while sending /exit"))
}
async fn handle_session_update(&self, _foreground: &ModelSpawner<AgentDriver>) -> Result<()> {
self.handle_parent_bridge_session_update().await
}
async fn save_conversation(
&self,
save_point: SavePoint,
foreground: &ModelSpawner<AgentDriver>,
) -> Result<()> {
if matches!(save_point, SavePoint::Periodic)
&& !super::has_running_cli_agent(&self.terminal_driver, foreground).await
{
log::debug!("Will not save conversation, Claude Code not in progress");
return Ok(());
}
View on GitHub (pinned to e72fd7aacb)
Solutions
- Treat as non-fatal if the underlying session is already terminating — verify the claude CLI process is gone (ps aux | grep claude); kill it if it lingers.
- Ensure only one component drives exit/shutdown per session to avoid racing entity teardown.
- If processes leak regularly, capture logs around shutdown and report the lifecycle race against ModelSpawner/AgentDriver.
Example fix
// before
self.exit(&foreground).await?; // propagates 'dropped' error and fails shutdown
// after (tolerate dropped driver at exit)
if let Err(err) = self.exit(&foreground).await {
log::warn!("failed to send /exit (driver likely gone): {err:#}");
} Defensive patterns
Strategy: try-catch
Validate before calling
if foreground.is_dropped() { // or equivalent liveness check on the model handle
log::info!("agent driver already gone; skipping /exit");
return Ok(());
} Try / catch
if let Err(err) = self.exit(&foreground).await {
if err.to_string().contains("Agent driver dropped") {
log::warn!("driver gone before /exit; assuming session terminated");
return Ok(());
}
return Err(err);
} Prevention
- Drive shutdown from a single owner per session to avoid racing entity teardown.
- Treat dropped-driver errors at exit as success-equivalent (the session is ending anyway).
- Verify the CLI process actually terminated with a process check, not just the exit call.
When it happens
Trigger: Invoking exit() on the claude_code harness (shutdown path) while the AgentDriver foreground model is being torn down concurrently — e.g. the session was killed/crashed first, or two shutdown paths race so the model handle is dropped before the spawned closure executes.
Common situations: Rapid double-exit (user quits while cleanup runs); agent process already dead so the framework drops the driver mid-exit; app shutdown tearing down entities while a harness exit future is still pending. Usually cosmetic: the CLI session is ending anyway.
Related errors
- Agent driver dropped while starting Claude message bridge
- could not determine home directory
- could not determine home directory
- could not determine home directory
- Timed out refreshing team metadata
AI-assisted analysis of warpdotdev/warp@e72fd7aacb (2026-08-16).
Data as JSON: /api/errors/a57ddba55d2a5f30.
Report an issue: GitHub.