`--permission-mode dontAsk` denies Write even when `Write(/tmp/**)` is in allowlist; Bash with same glob breadth works

Resolved 💬 3 comments Opened Apr 24, 2026 by ph47s74x Closed Apr 28, 2026

Summary

With --permission-mode dontAsk and .claude/settings.local.json containing "Write(/tmp/**)" in the allow list, the Write tool is still silently denied for paths like /tmp/reserve-payload-builder.md. The agent reports the tool being blocked and halts. The same session can successfully invoke Bash(cat > /tmp/foo.md <<EOF …) because "Bash(*)" is also in the allowlist.

Reproduction

.claude/settings.local.json:

{
  "permissions": {
    "allow": [
      "Bash(*)",
      "Read(**)",
      "Read(/mnt/**)",
      "Read(/tmp/**)",
      "Write(**)",
      "Write(/**)",
      "Write(/tmp/**)",
      "Edit(**)"
    ]
  }
}

Launch with --permission-mode dontAsk, then have the agent attempt Write(/tmp/foo.md, "hello"). The agent surfaces:

The Write tool is being blocked by the don't-ask permission mode. I need Write access to /tmp/foo.md to complete this task

Despite Write(/tmp/**) matching.

Workaround: instruct the agent to use Bash(cat > /tmp/foo.md <<EOF … EOF) instead. That path works consistently — 25+ consecutive successes across parallel peers.

Scope

  • Reproduces consistently with Claude Code 2.1.117 headless sessions launched via screen + claude --permission-mode dontAsk.
  • Happens for both top-level Write(/tmp/**) and broader Write(**) globs.
  • Bash(*) with the same glob breadth works (so it's specific to the Write tool's match path, not a general dontAsk bug).
  • Interactive sessions with the same allowlist can prompt → approve → success, so the allowlist entry is structurally correct.

Suggested fix / investigation

  • The dontAsk permission resolver may be matching against a different canonicalized path than the allowlist glob (e.g. symlink-resolved, whereas the allowlist sees literal).
  • Or dontAsk may fall back to "only allow exact-path matches" vs the dialog path which allows glob matches.
  • Compare the code path for askPermission(Write, path) between default mode (opens dialog, dialog checks allowlist via one matcher) and dontAsk mode (denies silently, uses another matcher?).

Environment

  • Claude Code: 2.1.117
  • OS: Windows 11 + WSL2 Ubuntu 22.04 (peer sessions run inside WSL)
  • Launch: screen -dmS <name> claude --model sonnet --mcp-config ... --permission-mode dontAsk -- <prompt>

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗