Trust dialog suppressed by ancestor trust while permission loading exact-matches the workspace key — subfolder permissions silently dropped with no interactive remedy

Status Fixed / completed
Reported on v2.1.193
Maintainer reply None cached
Activity 6 comments · opened Jul 1, 2026 · closed Aug 15, 2026

Versions affected: introduced in 2.1.193; still present in 2.1.197 (latest) and 2.1.198 (next).

Repro

  1. Trust a plain (non-git) parent directory by running claude there and accepting the trust dialog.
  2. In a subfolder (non-git, or its own git root), add .claude/settings.json with permissions.allow entries.
  3. Run claude in the subfolder → stderr shows "Ignoring N permissions.allow entries… this workspace has not been trusted" — and no trust dialog ever appears.

Root cause
Two trust checks disagree:

  • checkHasTrustDialogAccepted (gates the TrustDialog at startup) walks up ancestor directories in ~/.claude.json projects — any trusted ancestor suppresses the dialog.
  • isWorkspacePersistedTrusted (gates permission-rule loading) exact-matches the workspace key: gitRoot(cwd) ?? resolve(cwd) — no ancestor walk.

In the mismatch state, project permissions.allow rules and additionalDirectories are dropped, and the warning tells the user to "run Claude Code interactively here once and accept the trust dialog" — which the ancestor-walking check guarantees can never appear. Only subfolders outside the trusted parent's git repo are affected; same-repo subfolders resolve to the trusted git root and work correctly.

Impact
Reported by an enterprise customer (who independently root-caused it via strings on the binary). Managed fleets on ≥2.1.196 hit this on any non-git multi-project directory layout. The only remedy is a manual ~/.claude.json edit: projects["<exact path printed in the warning>"].hasTrustDialogAccepted: true.

Suggested direction
Align the dialog gate to the same exact-match workspace key so the dialog is shown in the subfolder. The reverse fix (honoring ancestor trust in permission loading) would weaken the trust model, so exact-match on both sides looks like the safe alignment.

Related: #72507, #72610 (same symptom family — trust dialog unreachable while permissions are gated — different triggers), #71562.

View original on GitHub ↗

5 Comments

github-actions[bot] · 2 months ago

Found 2 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/72547
  2. https://github.com/anthropics/claude-code/issues/67319

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

markso-ops · 2 months ago

Not a duplicate of #72547 or #67319 — same symptom family (trust dialog unreachable while permissions are gated), different mechanism. #72547 is the session being misdetected as non-interactive and #67319 is VS Code extension-specific. This issue reproduces in a plain interactive CLI session: the dialog gate (checkHasTrustDialogAccepted) walks up ancestor directories and finds the trusted parent, so it intentionally skips the dialog, while permission loading (isWorkspacePersistedTrusted) exact-matches the cwd/git-root key and gates the rules. Fixing either of the other two would not resolve this one.

argothiel · 2 months ago

Hit this exact mismatch today on 2.1.197 (Linux/WSL2), with an extra twist worth documenting: the trusted ancestor in my case is / itself.

Setup: ~/.claude.json contains projects["/"].hasTrustDialogAccepted: true from a session run in / months ago (long before 2.1.193). Since / is an ancestor of everything, the ancestor-walking dialog gate suppresses the trust dialog in every directory on the machine, while the exact-match permission gate drops rules everywhere that lacks its own key.

Symptom: launching claude interactively in $HOME prints Ignoring 39 permissions.allow entries from .claude/settings.local.json: this workspace has not been trusted... and no dialog ever appears. The untracked-in-git fallback for local settings doesn't rescue it either: $HOME is not a git repo, so git ls-files --error-unmatch .claude/settings.local.json exits 128 and the file is treated as unverifiable.

Both remedies suggested by the warning fail:

  1. "Run Claude Code interactively here once and accept the trust dialog" — impossible; the ancestor walk guarantees the dialog never fires.
  2. "Set projects["$HOME"].hasTrustDialogAccepted: true in ~/.claude.json" — the edit is silently reverted if any Claude session is running (config rewritten from the app's write path; observed the flag flip back to false within a minute). Nothing warns you that all sessions must be closed first.

Workaround that worked: with all sessions exited, delete the projects["/"] entry, relaunch — the dialog fires again and accepting it sets the exact-match key.

Agree with @markso-ops this is not a duplicate of #72547 / #67319 — plain interactive CLI, session correctly detected as interactive, no VS Code involved.

🤖 Comment co-authored-by: Claude Fable 5

BGMLAI · 1 month ago

The safest fix is to define one canonical workspace identity function and use it for both trust UI and rule loading. Two independently implemented trust predicates will keep drifting. I would also make the failure closed and actionable: if permission rules are dropped, show the exact canonical key and expose a supported trust command rather than requiring direct state-file edits. Regression coverage should include plain parent/subfolder, nested git roots, symlinks, case differences, and a trusted ancestor with an untrusted child.

Fohdeesha · 1 month ago

this bit me hard on a couple projects, and it ended up being due to them being on mapped network drives, and claude's path not matching gits project path I believe - git project root was the network drive d:/etc/blah, while claude's was the share's IP / UNC path eg //192.168.1.2/etc/blah - it told me to paste this sorry for the slop but it seems accurate byeee

Mapped network drive + UNC git root: trust key can never match, so the workaround is mandatory (v2.1.209)

Confirming this on VS Code extension 2.1.209 (issue reports 2.1.193–2.1.198, so the affected range extends further than currently documented), and adding a variant I don't see mentioned yet: when the repo is opened via a mapped drive letter but git reports the root as UNC, the trust key can never be written correctly by any UI flow.

Why this variant is worse than the general case

Per the mechanism described in this issue, isWorkspacePersistedTrusted exact-matches on gitRoot(cwd) ?? resolve(cwd). On a mapped network drive those two disagree in form, not just in value:

cwd / VS Code workspace   ->  d:/Projects/my-repo
git rev-parse --show-toplevel  ->  //NAS/Share/Projects/my-repo     <-- UNC, and it WINS (git root exists)
~/.claude.json project key     ->  d:/Projects/my-repo              <-- the only key anything ever writes

The gate looks up the UNC string; .claude.json is keyed on the drive letter; the lookup misses; all project-scope permissions.allow rules are silently dropped. No warning is logged.

The critical consequence: accepting a trust dialog would not fix this even if one appeared, because the dialog writes the key for the workspace path (d:/…), not the git root (//NAS/…). The two gates disagree about identity, not just about ancestry. Combined with #34913 (the VS Code extension never shows the CLI's trust prompt), there is no in-product path to a working state — the manual ~/.claude.json edit isn't a convenience workaround here, it's the only option.

Symptom (diagnostic fingerprint)

A very specific split that makes this easy to misdiagnose for hours:

| Rule location | Trust-gated? | Result |
|---|---|---|
| ~/.claude/settings.json (user scope) | No | Never prompts |
| .claude/settings.json (project) | Yes | Always prompts |
| .claude/settings.local.json (project, if committed) | Yes | Always prompts |

In my case every mcp__<server>__* tool prompted despite all 50 tools being listed explicitly by name in .claude/settings.json, while Bash/Read/Grep/WebFetch never prompted — purely because those happened to be allowed in user scope. That split is the tell. It sends you off editing project settings syntax, which cannot possibly work, and .claude/settings.local.json gets caught by the same gate the moment it's committed to git.

Fix that works

Add hasTrustDialogAccepted: true under the UNC-form key in ~/.claude.json — byte-for-byte what git rev-parse --show-toplevel returns:

"projects": {
  "//NAS/Share/Projects/my-repo": {
    "hasTrustDialogAccepted": true
  }
}

Verified working: MCP tools that prompted on every call now run with no prompt, and the hand-written keys survive a reload (the harness does not prune or rewrite them). I added the backslash variant and the d:/ key as belt-and-braces, but the forward-slash UNC key is the one that matches git rev-parse output.

⚠️ Edit this file with node, not PowerShell. ConvertTo-Json in PS 5.1 defaults to -Depth 2 and will silently mangle a large nested config. I round-tripped JSON.parseJSON.stringify(_, null, 2) and confirmed byte-identical output before writing, then re-validated with an independent parser.

Suggested resolutions, in order of preference
  1. Align the two gates on one key strategy. They currently disagree, which is the root defect.
  2. Normalize the trust key so a mapped drive letter and its UNC target resolve identically (or key on both).
  3. At minimum, log the key being looked up when project rules are dropped. Right now the failure is completely silent, and the existing warning tells you to accept a dialog that never appears and would not help if it did. A single line naming the missed key would have turned a multi-hour dead-end into a one-minute fix.

Showing cached comments. Read the full discussion on GitHub ↗