zed-industries/zed · warning

authorization receiver was dropped

Error message

authorization receiver was dropped

What it means

Permission outcomes are delivered to the awaiting side over an mpsc channel; if the receiver was dropped (the awaiter was cancelled, timed out, or its turn already finished), send() fails and this anyhow context is logged via log_err(). It means the authorization resolution arrived after nobody was left to consume it — a late answer, not lost user data.

Source

Thrown at crates/agent/src/agent.rs:2225

                                        tool_call, options, kind, cx,
                                    )
                                })??;
                                cx.background_spawn(async move {
                                    let outcome = match outcome_task.await {
                                        acp_thread::RequestPermissionOutcome::Selected(outcome) => outcome,
                                        acp_thread::RequestPermissionOutcome::InterruptedByFollowUp => {
                                            acp_thread::SelectedPermissionOutcome::new(
                                                acp::PermissionOptionId::new(
                                                    FOLLOW_UP_PERMISSION_DENIED_OPTION_ID,
                                                ),
                                                acp::PermissionOptionKind::RejectOnce,
                                            )
                                        }
                                        acp_thread::RequestPermissionOutcome::Cancelled => return,
                                    };
                                    response
                                        .send(outcome)
                                        .map_err(|_| anyhow!("authorization receiver was dropped"))
                                        .log_err();
                                })
                                .detach();
                            }
                            ThreadEvent::ToolCallAuthorizationResolved {
                                tool_call_id,
                                outcome,
                            } => {
                                acp_thread.update(cx, |thread, cx| {
                                    thread.authorize_tool_call(tool_call_id, outcome, cx);
                                })?;
                            }
                            ThreadEvent::ToolCall(tool_call) => {
                                acp_thread.update(cx, |thread, cx| {
                                    thread.upsert_tool_call(tool_call, cx)
                                })??;
                            }
                            ThreadEvent::ToolCallUpdate(update) => {

View on GitHub (pinned to bc538def45)

Solutions

  1. No action usually needed — the awaiting side no longer cares; the log is noise, not corruption
  2. Dismiss pending permission prompts when a turn is cancelled to avoid the race
  3. If it fires frequently, audit for double-dispatched authorization requests
Defensive patterns

Strategy: try-catch

Try / catch

// In the responding task: a dropped receiver means the awaiter is gone.
if let Err(send_error) = response.send(outcome) {
    // Deliberately downgrade to a debug log: the awaiting side cancelled.
    log::debug!("permission response had no receiver: {send_error}");
}

Prevention

When it happens

Trigger: User answers a tool-call permission prompt after the requesting turn was cancelled or completed, so the receiving half of the channel was dropped; race between cancellation/timeout and the user's response.

Common situations: User leaves the permission dialog open, cancels the turn, then clicks allow/deny; a timeout resolves the prompt first and the user's later click hits the dead receiver.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/6c4aed25b3f873f6. Report an issue: GitHub.