zed-industries/zed · warning · anyhow::Error
{reason}
Error message
{reason} What it means
The tool call was denied automatically by permission rules rather than by a human: during the settings race, `check_settings` returned `ToolPermissionDecision::Deny(reason)`. The agent resolves the tool call with the deny outcome and fails it with the rule's own reason string, so the message content comes from settings evaluation, not this code.
Source
Thrown at crates/agent/src/thread.rs:6502
// status with an internal selected outcome. Dropping
// `response_rx` prevents the synthetic response from
// being delivered back into this loop.
match cx.update(|cx| check_settings(cx)) {
ToolPermissionDecision::Allow => {
drop(response_rx);
stream.resolve_tool_call_authorization(
&tool_call_id,
auto_allow_outcome.clone(),
);
return Ok(());
}
ToolPermissionDecision::Deny(reason) => {
drop(response_rx);
stream.resolve_tool_call_authorization(
&tool_call_id,
auto_deny_outcome.clone(),
);
return Err(anyhow!(reason));
}
ToolPermissionDecision::Confirm => continue,
}
}
}
}
})
}
/// Interprets a `SelectedPermissionOutcome` and persists any settings changes.
/// Returns `true` if the tool call should be allowed, `false` if denied.
fn persist_permission_outcome(
outcome: &acp_thread::SelectedPermissionOutcome,
fs: Option<Arc<dyn Fs>>,
cx: &AsyncApp,
) -> Result<()> {
let option_id = outcome.option_id.0.as_ref();
let err = || Err(anyhow!("Permission to run tool denied by user"));View on GitHub (pinned to bc538def45)
Solutions
- Read the reason string — it identifies the rule that denied the call; adjust or remove that rule in settings if the call is legitimate.
- Narrow overly-broad deny patterns or switch the tool back to 'ask' mode.
- Do not retry the identical call; change the approach or ask the user to update permissions.
Defensive patterns
Strategy: try-catch
Try / catch
match run_tool().await {
Err(err) if err.to_string() == deny_reason_from_settings => {
// Rule-driven denial: show the reason, do not retry the same call.
report_denied_to_user(err.to_string());
Ok(Default::default())
}
result => result,
} Prevention
- Keep deny rules narrow; prefer 'ask' over broad 'deny' patterns.
- Read the reason string before editing settings — it identifies the matching rule.
- Never auto-retry a settings-denied call; change approach or permissions.
When it happens
Trigger: A deny rule matches the tool call — the user previously chose 'always deny' for this tool or command pattern, or a ruleset in settings denies it — and the evaluation fires either at prompt time or after a settings change re-triggers the check.
Common situations: An earlier 'Always deny' selection matching a broader pattern than intended; organization-wide settings with deny rules; the model retrying a tool that rules now block.
Related errors
- authorization receiver was dropped
- Invalid model ID {}
- no language model configured
- Failed to send tool call authorization: {error}
- missing auto-resolution outcomes
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/8e168fd03ce88af2.
Report an issue: GitHub.