{"record":{"id":"6c4aed25b3f873f6","repo":"zed-industries/zed","slug":"authorization-receiver-was-dropped","errorCode":null,"errorMessage":"authorization receiver was dropped","messagePattern":"authorization receiver was dropped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/agent/src/agent.rs","lineNumber":2225,"sourceCode":"                                        tool_call, options, kind, cx,\n                                    )\n                                })??;\n                                cx.background_spawn(async move {\n                                    let outcome = match outcome_task.await {\n                                        acp_thread::RequestPermissionOutcome::Selected(outcome) => outcome,\n                                        acp_thread::RequestPermissionOutcome::InterruptedByFollowUp => {\n                                            acp_thread::SelectedPermissionOutcome::new(\n                                                acp::PermissionOptionId::new(\n                                                    FOLLOW_UP_PERMISSION_DENIED_OPTION_ID,\n                                                ),\n                                                acp::PermissionOptionKind::RejectOnce,\n                                            )\n                                        }\n                                        acp_thread::RequestPermissionOutcome::Cancelled => return,\n                                    };\n                                    response\n                                        .send(outcome)\n                                        .map_err(|_| anyhow!(\"authorization receiver was dropped\"))\n                                        .log_err();\n                                })\n                                .detach();\n                            }\n                            ThreadEvent::ToolCallAuthorizationResolved {\n                                tool_call_id,\n                                outcome,\n                            } => {\n                                acp_thread.update(cx, |thread, cx| {\n                                    thread.authorize_tool_call(tool_call_id, outcome, cx);\n                                })?;\n                            }\n                            ThreadEvent::ToolCall(tool_call) => {\n                                acp_thread.update(cx, |thread, cx| {\n                                    thread.upsert_tool_call(tool_call, cx)\n                                })??;\n                            }\n                            ThreadEvent::ToolCallUpdate(update) => {","sourceCodeStart":2207,"sourceCodeEnd":2243,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/agent/src/agent.rs#L2207-L2243","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["No action usually needed — the awaiting side no longer cares; the log is noise, not corruption","Dismiss pending permission prompts when a turn is cancelled to avoid the race","If it fires frequently, audit for double-dispatched authorization requests"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// In the responding task: a dropped receiver means the awaiter is gone.\nif let Err(send_error) = response.send(outcome) {\n    // Deliberately downgrade to a debug log: the awaiting side cancelled.\n    log::debug!(\"permission response had no receiver: {send_error}\");\n}","preventionTips":["Cancel/dismiss open permission prompts when their turn is cancelled","Do not retry the send — nobody is listening; just stop","Treat this log as expected noise in cancellation races, not a defect to chase"],"tags":["rust","zed","agent","permissions","race","channels"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}