zed-industries/zed · warning
Permission denied: user sent a follow-up message instead of
Error message
Permission denied: user sent a follow-up message instead of approving the tool call.
What it means
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.
Source
Thrown at crates/agent/src/thread.rs:1163
acp_thread::PermissionOptions::Dropdown(choices)
}
}
#[derive(Debug)]
pub struct ToolCallAuthorization {
pub tool_call: acp::ToolCallUpdate,
pub options: acp_thread::PermissionOptions,
pub response: oneshot::Sender<acp_thread::SelectedPermissionOutcome>,
pub context: Option<ToolPermissionContext>,
pub kind: acp_thread::AuthorizationKind,
}
fn ensure_tool_call_authorization_not_interrupted(
outcome: &acp_thread::SelectedPermissionOutcome,
) -> Result<()> {
if outcome.option_id.0.as_ref() == FOLLOW_UP_PERMISSION_DENIED_OPTION_ID {
Err(anyhow!(TOOL_CALL_INTERRUPTED_BY_FOLLOW_UP_MESSAGE))
} else {
Ok(())
}
}
fn auto_resolve_permission_outcome(
options: &acp_thread::PermissionOptions,
is_allow: bool,
) -> Result<acp_thread::SelectedPermissionOutcome> {
let kind = if is_allow {
acp::PermissionOptionKind::AllowOnce
} else {
acp::PermissionOptionKind::RejectOnce
};
let option = options
.first_option_of_kind(kind)
.ok_or_else(|| anyhow!("permission prompt has no auto-resolution option"))?;
View on GitHub (pinned to bc538def45)
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.
Defensive patterns
Strategy: try-catch
Try / catch
match ensure_tool_call_authorization_not_interrupted(&outcome) {
Ok(()) => { /* proceed with the tool call */ }
Err(e) if e.to_string().contains("follow-up message") => {
// permission superseded: mark tool call as interrupted, not failed;
// the agent will re-plan from the user's new message
}
Err(e) => return Err(e),
} Prevention
- Do not push user messages while a ToolCallAuthorization response is pending.
- Present this denial as 'superseded by your message' in UI copy.
When it happens
Trigger: 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.
Common situations: Users revising instructions mid-approval; permission dialogs left open while the user keeps chatting; automated clients pushing user messages while authorization is outstanding.
Related errors
- output token limit reached
- message not found
- not supported
- no thread found with ID: {id:?}
- Project state not found for session
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/3cca32e909290c66.
Report an issue: GitHub.