[BUG] `Write` (and `Edit`) tools strip the worktree path segment, writing to the parent repo instead
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Bug — Write (and Edit) tools strip the worktree path segment, writing to the parent repo instead
Affects: Claude Code 2.1.128 on macOS Darwin (arm64).
Severity: HIGH — silent cross-branch contamination. Files intended for an isolated worktree branch land on the parent repo's working tree and can be picked up by concurrent git operations (e.g. another Claude Code session running on the parent repo) and committed to a different branch.
TL;DR
When operating inside a git worktree located at <repo>/.claude/worktrees/<name>/, the Write tool silently strips the .claude/worktrees/<name>/ segment from the file path and writes to <repo>/<rest-of-path> (the parent repo). The path passed to the tool is absolute and correct; the strip happens inside the tool.
The Edit tool behaves differently but is also broken: it reports success while neither the worktree file nor the parent repo file is actually modified — silent no-op.
Both bugs combine catastrophically when a separate Claude Code session is running on the parent repo (e.g. a background grinder / loop runner). That session's git add operation can sweep up the orphan files and commit them to a different branch, contaminating it without anyone realizing.
Environment
- Claude Code:
2.1.128 - OS:
Darwin 25.x arm64(macOS, Apple-Silicon hardware) - Git:
2.50.x (Apple Git) - Shell:
zsh - Worktree topology (the documented Claude Code pattern for
isolation: "worktree"):
<repo>/ ← main checkout, current branch = X
<repo>/.claude/worktrees/<name>/ ← worktree, current branch = Y
.claude/worktrees/ is gitignored in the parent repo, so the worktree is isolated by design.
What Should Happen?
Not spill data editing changes to active branch
Error Messages/Logs
Steps to Reproduce
Reproduction
- Open a Claude Code session in a worktree at
<repo>/.claude/worktrees/<name>/(e.g. via the Agent tool withisolation: "worktree"). - From that session, call the
Writetool with an absolute path inside the worktree:
````
file_path: <repo>/.claude/worktrees/<name>/.plan/example.md
content: "# Test"
- Write returns
"File created successfully at: <full-path>"— appears successful. - From within the worktree, run
ls <repo>/.claude/worktrees/<name>/.plan/example.mdvia Bash — file does not exist. - From within the worktree, run
ls <repo>/.plan/example.mdvia Bash — file IS there (parent repo, NOT the worktree). - If the parent repo currently has a different branch checked out and is being used by a concurrent process, that file is now sitting in that branch's working tree, awaiting
git add.
What I observed in a real session
- Worktree on branch
feature/<worktree-name>. Parent repo had a concurrent agent process running on branchfeature/<concurrent-branch>. - Write call:
````
file_path: <repo>/.claude/worktrees/<worktree-name>/.plan/<example-file>.md
reported success.
lson the same absolute path returned "No such file or directory".- I assumed Write failed and re-created the file via
cat > heredoc(which correctly wrote to the worktree). - Later, the user reported from the OTHER Claude Code session: "that file ended up in our branch."
- Investigation showed the Write-tool file at
<repo>/.plan/<example-file>.md(parent repo —.claude/worktrees/<worktree-name>/had been stripped from the path). - The concurrent agent's next
git add(broad pattern) committed the orphan file to its branch as part of an unrelated commit.
File evidence (two copies on disk after the heredoc fallback):
<mtime-1> <size-1> <repo>/.plan/<example-file>.md
(Write tool — wrong location, parent repo)
<mtime-2> <size-2> <repo>/.claude/worktrees/<worktree-name>/.plan/<example-file>.md
(heredoc fallback — correct location)
Mtime delta ≈ 1m45s — Write's misdirected write came first, the heredoc came second.
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.128
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
Companion bug — Edit tool in the same setup
Same worktree, several Edit calls earlier in the session targeting files inside the worktree:
- Each Edit call returned
"The file ... has been updated successfully." git status/git diffon the worktree showed no changes.- Bash
grepfor the new content on both the worktree AND the parent repo's working tree returned the original content — neither version of the file was actually modified. - Subsequent
sed -i ''calls via Bash on the same patterns succeeded — proving the file was writable and the search patterns were valid.
Edit here is a silent no-op rather than a silent misdirect — but it's just as misleading because the harness reports success and proceeds.
Workaround
Until fixed, in worktree sessions:
- Don't use
WriteorEdit. - Use Bash for all file changes:
- New file:
cat > path << 'EOF' ... EOF - Edit:
sed -i '' 's|old|new|' path - Bash respects pwd correctly; pwd in a worktree session is the worktree.
Suggested fix direction
The Write tool's file-creation path likely resolves through some abstraction that strips paths it considers "outside the canonical repo root" — .claude/worktrees/... would qualify as ".claude is a Claude-internal folder, strip it." That heuristic is wrong for the worktree case: .claude/worktrees/<name>/ is the actual working tree.
The Edit tool's no-op may share the same root cause (path resolution sends the call to a sandbox/snapshot it can't write back from).
Suggested checks:
- Detect git worktree mode (
git rev-parse --git-dirreturns<parent-repo>/.git/worktrees/<name>when inside a worktree) and bypass any "strip Claude-internal paths" logic. - For the Edit tool, surface the actual disk-write outcome rather than reporting blanket success.
Why this matters at scale
Anyone using isolation: "worktree" mode (the documented Claude Code pattern for parallel agent work) + a concurrent process on the parent repo (grinder, loop runner, manual coding session, another Claude Code instance) can have files silently cross-contaminate between branches. The user may not notice for hours; the contamination only surfaces when:
- Someone reads the wrong branch's tree, OR
- A
git add -Aoperation in the parallel session sweeps up the orphan file, OR - A rebase produces inexplicable conflicts.
For multi-session workflows this can quietly corrupt commit history on the parent branch.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗