anthropics / anthropics/claude-code

Background Agent subagent's worktree/Bash sandbox gets redirected by parent session's later EnterWorktree call

Ouverte
#89,254 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
area:agents area:sandbox bug has repro
Langage dominant
Python
Étoiles
145k
Forks
23.1k
Métriques de merge des PR
Métriques de PR en attente

Description

## Summary

A background `Agent`-tool subagent's Bash sandbox isolation appears to track the **parent session's live `EnterWorktree` pin**, not a value fixed when the subagent was dispatched. If the parent session calls `EnterWorktree` (to a different path, for unrelated work) while a background subagent is still mid-task in its own worktree, the subagent's subsequent Bash commands are refused/redirected toward the parent's *new* pin instead of the worktree it was actually assigned.

This is dangerous because a subagent that isn't watching for it can end up executing file writes (including `git checkout --`, commits, etc.) against the wrong working tree — in our case, briefly clobbering the subagent's own uncommitted work when the parent (unaware anything had gone wrong) ran an ordinary cleanup command against what it reasonably believed was an unrelated, empty directory.

## Repro (confirmed, reproduced deliberately)

1. Parent session calls `EnterWorktree({ name: "some-path" })`, dispatches a background `Agent` subagent to do file-writing work. The subagent is not given `isolation: "worktree"` — it's instructed via its prompt to create and navigate to its own worktree/branch itself.
2. Subagent creates its own worktree (e.g. via `git worktree add`) and begins editing files there — confirmed via its own `pwd`/`git branch --show-current` output at the time.
3. While the subagent is still running, the **parent** session calls `EnterWorktree({ path: "" })` for its own separate task.
4. The subagent's next Bash tool call is refused, with a sandbox message naming the **parent's new worktree** as "the shared checkout" and telling the subagent to re-run its command from there — even though the subagent never called `EnterWorktree` itself and has no reason to think its assigned location changed.
5. We tested the mechanism directly: with the parent's pin sitting at path A, the subagent's Bash calls targeting its own (different) worktree B were refused, naming A. When the parent then called `EnterWorktree({ path: B })` (matching the subagent's actual assigned worktree) and the subagent additionally called `EnterWorktree({ path: B })` on its own side too, its Bash calls then succeeded there. Moving the parent's pin is what gated whether the subagent's commands worked at all — the subagent's own `EnterWorktree` calls alone did not fix it while the parent's pin was elsewhere.

## Impact observed

- A background subagent's ~150 lines of uncommitted work (a schema/validator addition) were briefly destroyed when the parent, believing a directory had accumulated unrelated stray files, ran `git checkout -- ` against what turned out to be the subagent's real in-progress work — because the subagent's writes had landed in the parent's currently-pinned worktree rather than its own. Recovered without permanent loss only because the subagent still had the content in its own context and could restate it verbatim.
- A second, differently-shaped incident the same day (possibly the same root cause, possibly a distinct issue — see below): a different background subagent, told to create its own worktree, encountered a benign/transient git message (`failed to store: 100001` / `could not lock config file` — a credential-helper artifact that in our experience never corresponds to a real git failure) while attempting `git worktree add`, and — rather than retrying — concluded it should work in "its already-assigned worktree," which turned out to be the parent session's own home worktree. This may be the same underlying mechanism surfacing differently, or an unrelated model-behavior issue (treating a benign warning as a hard failure). We were not able to cleanly separate the two explanations.

## Model tiers observed

- The **confirmed, deliberately-reproduced** instance (the numbered repro above) was on **Opus**.
- The second, differently-shaped incident was on **Sonnet** — but as noted above, we can't be certain it's the identical bug rather than a related-but-distinct failure mode.
- A third incident was reported by a peer Claude Code session on the same machine, same day, writing to the same repo — it found its own uncommitted content (an appendix to a planning doc) sitting in a worktree belonging to an already-merged branch, written via an absolute-path `Edit` tool call rather than a relative Bash path. That session flagged it as a possibly more serious variant, since an absolute-path edit landing in the wrong place would rule out ordinary relative-path/cwd confusion, but explicitly hedged that it couldn't rule out its own user/harness error either. We were unable to confirm that session's model tier before it completed its own task and its worktree was cleaned up.

## What we'd expect instead

Either:
- A background subagent's sandbox/worktree assignment is fixed at dispatch time and never affected by anything the parent session does afterward, or
- If a shared/global "current worktree" concept is intentional, a subagent should be told explicitly (not just refused with a generic message) that its assignment changed out from under it, so it can stop and report rather than silently working somewhere unintended.

## Workaround we've adopted

Passing `isolation: "worktree"` on the `Agent` tool call itself (letting the harness provision the subagent's worktree, rather than instructing the subagent to self-navigate via prompt) and avoiding any `EnterWorktree`/`ExitWorktree` call in the parent session while a background subagent is still running. Untested whether `isolation: "worktree"` fully closes this — we adopted it going forward but haven't yet deliberately re-reproduced the bug against it.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

Start by reproducing the numbered sequence using the Agent, EnterWorktree, and Bash tools, first with a self-created worktree and then with isolation: "worktree". Compare which worktree later Bash calls target after the parent changes its pin. Done means a background subagent's assignment remains stable, or it is explicitly warned when that assignment changes.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
bash, git
Domaine
cli, tooling
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
Active
Clarté
Plutôt claire
Accessibilité débutants
38/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.