[BUG] Desktop worktree Write/Edit guard blocks files in a separate git repo nested under the base checkout

Status Open
Reported on v2.1.282
Maintainer reply None cached
Activity 1 comment · opened Sep 26, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (related, not the same case: #95776, #95389)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

In a desktop-app session isolated in a worktree, the Write/Edit worktree guard blocks writes to files that belong to a different git repository nested inside the base repo's folder. The guard treats any path under the base checkout's directory as "the base repo checkout" without asking git which repository owns the path.

Layout (paths generalized):

~/work/company/                   <- repo A (base checkout); `products/` is gitignored here
~/work/company/.claude/worktrees/session-x/   <- this session's worktree of repo A
~/work/company/products/app/      <- repo B, its own .git, unrelated to repo A
~/work/company/products/app/.claude/worktrees/feature-y/   <- a worktree of repo B

A Write to ~/work/company/products/app/.claude/worktrees/feature-y/notes/x.md is blocked with:

This session is running in an isolated git worktree at ~/work/company/.claude/worktrees/session-x, but ~/work/company/products/app/.claude/worktrees/feature-y/notes/x.md is in the base repo checkout. Edits there do not land on this session's branch and may corrupt the user's primary working copy. Use the worktree path instead: ~/work/company/.claude/worktrees/session-x/products/app/.claude/worktrees/feature-y/notes/x.md

The target is not in repo A's checkout. git -C <target dir> rev-parse --show-toplevel --git-common-dir returns repo B's worktree and products/app/.git. The suggested replacement path does not exist and cannot exist, because products/ is gitignored in repo A.

Side effect: agents work around the block by writing the file through a Bash heredoc, which the guard does not see (the same Edit-vs-Bash asymmetry reported in #95776). So the guard adds friction here without adding protection, and it teaches the agent to route around it.

What Should Happen?

Before blocking, the guard should resolve the repository that owns the target (for example git rev-parse --git-common-dir from the nearest existing parent directory). It should block only when that common dir equals the session repo's common dir and the target is outside the session worktree. A path owned by a different repository should be allowed, or at least not described as the base repo checkout.

Error Messages/Logs

See the quoted block message above.

Steps to Reproduce

  1. Create repo A with a gitignored subfolder, and create repo B (git init) inside that subfolder.
  2. Open repo A in the Claude desktop app (Code tab) with a worktree-isolated session.
  3. Ask Claude to Write any file inside repo B, either repo B's main checkout or one of its worktrees.
  4. The Write is blocked as "in the base repo checkout", with a nonexistent suggested path.

Seen twice in real sessions on 2026-09-25. I have not reproduced it in a throwaway repo, because the guard is in the desktop app and does not run under the headless CLI. From reading the bundled app code, the check is a path-containment test against the base repo root with no repository-identity check, which matches the behaviour above.

Claude Model

Opus

Is this a regression?

I don't know

Claude Code Version

Desktop app 2.9939.2; Claude Code 2.1.282

Platform

Anthropic API

Operating System

macOS 26.6.2

Terminal/Shell

Claude desktop app (Code tab)

Additional Information

Related guard issues with the same root cause (path containment instead of repository identity): #95776 (a separate registered worktree under <base>/.claude/), #95389 (the guard keeps its original binding after EnterWorktree(path=...)).

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗