{"record":{"id":"3cca32e909290c66","repo":"zed-industries/zed","slug":"permission-denied-user-sent-a-follow-up-message-i","errorCode":null,"errorMessage":"Permission denied: user sent a follow-up message instead of approving the tool call.","messagePattern":"Permission denied: user sent a follow-up message instead of approving the tool call\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/agent/src/thread.rs","lineNumber":1163,"sourceCode":"\n        acp_thread::PermissionOptions::Dropdown(choices)\n    }\n}\n\n#[derive(Debug)]\npub struct ToolCallAuthorization {\n    pub tool_call: acp::ToolCallUpdate,\n    pub options: acp_thread::PermissionOptions,\n    pub response: oneshot::Sender<acp_thread::SelectedPermissionOutcome>,\n    pub context: Option<ToolPermissionContext>,\n    pub kind: acp_thread::AuthorizationKind,\n}\n\nfn ensure_tool_call_authorization_not_interrupted(\n    outcome: &acp_thread::SelectedPermissionOutcome,\n) -> Result<()> {\n    if outcome.option_id.0.as_ref() == FOLLOW_UP_PERMISSION_DENIED_OPTION_ID {\n        Err(anyhow!(TOOL_CALL_INTERRUPTED_BY_FOLLOW_UP_MESSAGE))\n    } else {\n        Ok(())\n    }\n}\n\nfn auto_resolve_permission_outcome(\n    options: &acp_thread::PermissionOptions,\n    is_allow: bool,\n) -> Result<acp_thread::SelectedPermissionOutcome> {\n    let kind = if is_allow {\n        acp::PermissionOptionKind::AllowOnce\n    } else {\n        acp::PermissionOptionKind::RejectOnce\n    };\n    let option = options\n        .first_option_of_kind(kind)\n        .ok_or_else(|| anyhow!(\"permission prompt has no auto-resolution option\"))?;\n","sourceCodeStart":1145,"sourceCodeEnd":1181,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/agent/src/thread.rs#L1145-L1181","documentation":"When a tool call is awaiting permission and the user sends a new message instead of choosing allow/deny, the pending authorization is interrupted: agent.rs maps RequestPermissionOutcome::InterruptedByFollowUp to a RejectOnce outcome carrying the sentinel option id FOLLOW_UP_PERMISSION_DENIED_OPTION_ID, and ensure_tool_call_authorization_not_interrupted converts that outcome into this error so the tool call ends with a clear reason.","triggerScenarios":"The user types a follow-up message while a permission prompt is pending for a tool call; the synthesized denial then fails the tool call with this message.","commonSituations":"Users revising instructions mid-approval; permission dialogs left open while the user keeps chatting; automated clients pushing user messages while authorization is outstanding.","solutions":["Re-prompt or re-issue the tool call: the follow-up message becomes the new instructions and the agent can retry the tool.","In UIs, present this as 'superseded by your message', not as a hard failure.","If it appears without user action, audit code paths that push user content while a ToolCallAuthorization is pending."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match ensure_tool_call_authorization_not_interrupted(&outcome) {\n    Ok(()) => { /* proceed with the tool call */ }\n    Err(e) if e.to_string().contains(\"follow-up message\") => {\n        // permission superseded: mark tool call as interrupted, not failed;\n        // the agent will re-plan from the user's new message\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Do not push user messages while a ToolCallAuthorization response is pending.","Present this denial as 'superseded by your message' in UI copy."],"tags":["rust","zed","agent","acp","permission","interruption"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}