claude-code - 💡(How to fix) Fix isolation: worktree subagents silently write outside the worktree via absolute file_path (Edit/Write target primary clone, not the isolated worktree)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

A subagent spawned with isolation: "worktree" has its cwd correctly set to the isolated worktree, but its Edit/Write/Read calls routinely target an absolute file_path rooted at the primary clone rather than the worktree. Because the harness nests worktrees under the primary clone (<repo>/.claude/worktrees/agent-<id>/), that absolute path resolves to a real, writable file on the primary clone's checked-out branch (e.g. main). The edit succeeds silently — no error — and the subagent's work lands on the wrong branch entirely, outside its isolation.

The isolation boundary is therefore advisory, not enforced: nothing stops a subagent from editing the parent checkout, and the most natural failure mode (absolute path = the canonical repo path the agent carries in context) points directly at the parent.

Error Message

A subagent spawned with isolation: "worktree" has its cwd correctly set to the isolated worktree, but its Edit/Write/Read calls routinely target an absolute file_path rooted at the primary clone rather than the worktree. Because the harness nests worktrees under the primary clone (<repo>/.claude/worktrees/agent-<id>/), that absolute path resolves to a real, writable file on the primary clone's checked-out branch (e.g. main). The edit succeeds silently — no error — and the subagent's work lands on the wrong branch entirely, outside its isolation. Guard Edit/Write (and Read/MultiEdit) in an isolation: worktree session: if the resolved absolute file_path falls outside the worktree root (git rev-parse --show-toplevel), reject the call with an error naming the worktree-relative path the agent should use. Deterministic; doesn't depend on prompt compliance. (Optionally: don't nest worktrees under the primary clone, so an out-of-worktree path can't resolve to a sibling file — but the guard is the robust fix.)

Root Cause

Edit/Write/Read require absolute file_path. The agent assembles it from the canonical repo path in its context (= primary clone), not from its actual worktree root. The harness does not fence Edit/Write to the worktree, and worktree-under-primary-clone nesting means the wrong path hits a real file. Result: mandated-absolute-path + salient-path-is-primary-clone + nested-worktree = silent escape.

RAW_BUFFERClick to expand / collapse

Summary

A subagent spawned with isolation: "worktree" has its cwd correctly set to the isolated worktree, but its Edit/Write/Read calls routinely target an absolute file_path rooted at the primary clone rather than the worktree. Because the harness nests worktrees under the primary clone (<repo>/.claude/worktrees/agent-<id>/), that absolute path resolves to a real, writable file on the primary clone's checked-out branch (e.g. main). The edit succeeds silently — no error — and the subagent's work lands on the wrong branch entirely, outside its isolation.

The isolation boundary is therefore advisory, not enforced: nothing stops a subagent from editing the parent checkout, and the most natural failure mode (absolute path = the canonical repo path the agent carries in context) points directly at the parent.

Why this is serious

  • Silent loss of isolation: the entire point of isolation: worktree is that a subagent can't touch the parent. It can, trivially, via any absolute path.
  • Silent wrong-branch writes: edits land uncommitted on the primary clone's branch (often main). The subagent's own verification (relative-path git diff/md5) inspects the worktree, sees no change, and misreports the write as a "flush failure" — so the agent doesn't even know it leaked.
  • Cross-session accumulation: leaked edits sit uncommitted on the primary branch indefinitely and get attributed to later sessions.

Evidence (observed in a real session)

Two subagents in one run, cwd correctly the worktree for 100% of records:

  • doc-updater: all 4 Edit/Write calls used the primary-clone absolute path -> all 4 leaked onto main. Agent concluded (wrongly) that the "write-path silently failed to flush," because its relative-path verification saw the unmodified worktree copy.
  • issue-developer: first 5 Edit calls used the primary-clone path (leaked), then it empirically detected the dirty primary clone, hand-reconstructed the worktree-rooted absolute path, and the next 5 calls were correct. So the correct absolute worktree path is constructible — the agent just defaults to the wrong root.

Across every subagent transcript in this project, 51/51 Edit/Write/MultiEdit calls used absolute paths; the agents never use relative. The absolute path they assemble defaults to the canonical repo root from context (the primary clone), not git rev-parse --show-toplevel of the worktree.

Root cause

Edit/Write/Read require absolute file_path. The agent assembles it from the canonical repo path in its context (= primary clone), not from its actual worktree root. The harness does not fence Edit/Write to the worktree, and worktree-under-primary-clone nesting means the wrong path hits a real file. Result: mandated-absolute-path + salient-path-is-primary-clone + nested-worktree = silent escape.

Suggested fix (harness-side)

Guard Edit/Write (and Read/MultiEdit) in an isolation: worktree session: if the resolved absolute file_path falls outside the worktree root (git rev-parse --show-toplevel), reject the call with an error naming the worktree-relative path the agent should use. Deterministic; doesn't depend on prompt compliance. (Optionally: don't nest worktrees under the primary clone, so an out-of-worktree path can't resolve to a sibling file — but the guard is the robust fix.)

Related but distinct

  • #52958 — cwd leaks into the parent. Here cwd is correct; the file_path escapes.
  • #47548 — setup-time isolation failure (parent branch switched). Here isolation sets up fine and is breached post-setup via path.

Environment

  • Claude Code: 2.1.150
  • Model: claude-opus-4-7 (Opus 4.7) — both the orchestrator and the two affected subagents (issue-developer, doc-updater) ran on this model
  • Platform: darwin 25.5.0
  • Repo shape: standard git repo, worktrees at <repo>/.claude/worktrees/agent-<id>/
  • Reproduced with both doc-updater and issue-developer subagent types in a single /issue-address orchestration run.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING