Bash deny-rule denial doesn't name the matching rule or its settings scope — server-managed deny rules are invisible to the developer they apply to
Version: 2.1.273 (desktop app, macOS)
Summary
When a Bash command is blocked by a permissions.deny rule, the denial identifies neither the rule that matched nor the settings scope it came from:
Permission to use Bash with command <cmd> has been denied.
When that deny rule arrives via server-managed settings (~/.claude/remote-settings.json), the rule is effectively invisible to the developer it applies to, and the natural debugging path leads away from the answer.
What happened
My organization's server-managed settings include a permissions.deny entry for a common command (Bash(ssh:*)). I did not know the file existed, let alone that the entry was in it.
Diagnosing the block took two sessions. Along the way I:
- checked all three documented
managed-settings.jsonpaths — absent - checked project settings, local settings, and hooks — no deny or ask rules anywhere
- concluded from the docs that a shell command carrying per-command allowed domains routes to the auto-mode classifier even when an allow rule matches, and therefore that the classifier was the decision point
- wrote
autoMode.environmententries describing the destination hosts as trusted infrastructure, and verified them live withclaude auto-mode config— entirely inert, because a deny rule short-circuits before the classifier is ever consulted - investigated sandbox network configuration — also irrelevant, since the sandbox proxies HTTP/HTTPS domains and the command in question isn't HTTP
None of that work was necessary. One line naming the rule would have ended it in seconds.
Contrast with classifier denials
Auto-mode classifier denials are informative — they name the matched rule and suggest remediation:
Permission for this action was denied by the Claude Code auto mode classifier.
Reason: [Auto-Mode Bypass]. ...
Deny-rule denials give neither piece of information. During the same session I received both kinds, and the asymmetry actively misled me: the verbose one named a cause, so I reasoned the terse one must be a different and unnamed layer, and went looking in the wrong subsystems.
Requested change
Include the matching rule and its settings scope in the denial message:
Denied by deny rule Bash(ssh:*) from server-managed settings.
Naming the scope alone would be enough to point the search in the right direction. Surfacing the rule to the user it already governs discloses nothing — they are the subject of the policy, not an adversary who needs to be kept unaware of it.
Why this case in particular
An administrator-deployed deny rule is the situation where a developer is least able to guess the cause: they have no visibility into the file, no memory of configuring it, and every local settings file they can inspect looks clean. That is currently the case with the least informative message.
Possibly unrelated, noticed in the same session
/auto-mode-setup returns Unknown command on 2.1.273 in the desktop app. The docs give its floor as v2.1.228 and list only cloud sessions and disabled feature-flag fetching as exclusions; neither applies here. May be a surface gap or a docs gap — happy to split this into its own issue.