Agent tool with isolation:"worktree" silently reuses stale branches on agentId-prefix collision

Resolved 💬 2 comments Opened Apr 21, 2026 by scottmeyer Closed Apr 22, 2026

Summary

When the Agent tool is called with isolation: "worktree", Claude Code derives the worktree's git branch name from an 8-hex-char prefix of the subagent's agentId (worktree-agent-<8hex>). If a branch with that name already exists from a prior session, the worktree is silently reused — including that branch's uncommitted files, stash stack, and whatever state was left behind. This led to contamination of a new subagent's work with a 2-day-old session's leftover changes, with no warning in the subagent's context that the worktree wasn't freshly created.

Reproduction (observed today)

  1. Prior session (2 days ago) used Agent(isolation:"worktree") which created branches worktree-agent-aae6004a and worktree-agent-abb767eb. Those sessions ended with uncommitted changes and git stash entries on those branches (e.g. stash@{3}: On main: other-agent WIP (policy/keys/attestation/etc.)).
  2. Today, a new session called Agent(isolation:"worktree") twice. The new subagents were assigned agentIds aae6004a1fe933672 and abb767eb49c7841fc — whose 8-hex prefixes collide exactly with the 2-day-old branches.
  3. Claude Code's worktree setup found the existing branches, reused them instead of creating fresh ones, and the subagents inherited:
  • 10 stacked stashes (including work labeled "other-agent WIP")
  • Uncommitted file modifications from prior sessions
  • An outdated base (e47a4073, 2 days old) instead of current main (d89ba7d2)
  1. One subagent followed a rebase-and-stash-pop recovery path per the user's instruction, and the git stash pop auto-merged a stale rename (CORE_PRIMITIVESCORE_PRIMITIVES_FALLBACK) plus stray doc-comment edits into its work. The contamination passed tests + clippy because it was semantically compatible; only a careful manual diff audit caught the out-of-scope hunks.
  2. The second subagent crashed after 380 tool_uses / 31 minutes with \"Prompt is too long\", never committing anything. Its worktree was left with cross-scope files (including test files that belonged to the OTHER subagent's scope) — suggesting even more state leakage in the reused environment.

Impact

  • Silent data corruption of agent output. Stale work from an orphaned prior session was merged into a new commit claiming to address a specific needle. The contaminated commit needed a post-hoc manual audit to discover. A less-attentive user would have merged the polluted commit to main.
  • Wasted agent time / cost. The second agent burned 31 minutes of sonnet wall-time fighting a contaminated worktree before context-overflow killed it, producing zero output.
  • Cross-scope file leakage. Files created by one subagent appeared in the other subagent's worktree, indicating the worktrees are not as isolated as the API name suggests.

Expected behavior

  • On isolation: \"worktree\", the tool should refuse to reuse an existing branch+worktree. Either:
  • Option A: always create a fresh, uniquely-named worktree (append timestamp or longer agentId prefix) — and guarantee the starting tree is clean (no stashes, no untracked files, no stale uncommitted work).
  • Option B: if a branch with the derived name already exists, either error loudly (\"branch name collision; pass explicit branch\") or hard-reset the worktree to the intended base (HEAD of the calling session) + git clean -fdx + git stash clear before handing control to the subagent.
  • The subagent should be told the worktree is freshly created (explicitly, in the system prompt or equivalent) so it can trust its base.
  • agentId prefix collisions should be either impossible (longer prefix) or explicitly handled.

Environment

  • macOS 15.4
  • Claude Code version: current as of 2026-04-21
  • Subagent type: general-purpose with model: sonnet
  • isolation: \"worktree\" via main session's Agent tool

Suggested fix priority

High — this is silent data corruption in a feature whose name (\"worktree isolation\") implies the opposite property.

Workaround

Block Agent calls with isolation: \"worktree\" via a PreToolUse hook. The user had already written ~/.claude/hooks/block-worktree.sh for exactly this purpose; it just wasn't wired into settings.json at the time the incident happened. Wiring it now prevents recurrence.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗