[BUG] `claude -w` can't remove a clean worktree on exit when launched inside a git submodule

Status Open
Reported on v2.1.300
Maintainer reply None cached
Activity 0 comments · opened Oct 15, 2026

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?

When I run claude -w inside a git submodule and exit a session without making changes, Claude Code prints "Worktree could not be removed" and leaves the worktree directory and its worktree-* branch behind.

The leftover worktree has nothing that should block removal. Its HEAD matches main, git status is clean, it isn't locked, and running git worktree remove on it by hand succeeds.

Running claude -w in the submodule's origin repo, a standalone repo with the same commit, removes the worktree as expected.

What Should Happen?

A clean, unnamed worktree created inside a submodule is removed on exit, the same as in a standalone repo:

Removing worktree…
Worktree removed (no changes)

Error Messages/Logs

~/claude-wt-repro/parent/child (main) % claude -w
# exit immediately
Removing worktree…
Worktree could not be removed — kept at ~/claude-wt-repro/parent/child/.claude/worktrees/shimmering-stirring-simon

~/claude-wt-repro/parent/child (main) % git worktree list --porcelain
worktree ~/claude-wt-repro/parent/.git/modules/child
HEAD 7e7224347acc815b391d61e962d3f33ac4a3ea73
branch refs/heads/main

worktree ~/claude-wt-repro/parent/child/.claude/worktrees/shimmering-stirring-simon
HEAD 7e7224347acc815b391d61e962d3f33ac4a3ea73
branch refs/heads/worktree-shimmering-stirring-simon

~/claude-wt-repro/parent/child (main) % git -C .claude/worktrees/shimmering-stirring-simon status --short --branch
## worktree-shimmering-stirring-simon

~/claude-wt-repro/child-origin (main) % claude -w
# exit immediately
Removing worktree…
Worktree removed (no changes)

Steps to Reproduce

  1. Create a repo to use as the submodule's origin:

``sh
git init -b main child-origin
cd child-origin
echo '# child' > README.md
echo '.claude/worktrees/' > .gitignore
git add . && git commit -m "init child"
cd ..
``

  1. Create a parent repo and add child-origin as a submodule:

``sh
git init -b main parent && cd parent
echo '# parent' > README.md && git add . && git commit -m "init parent"
git clone ../child-origin child
git submodule add ../child-origin child
git submodule absorbgitdirs
git commit -m "add child submodule"
`
This yields the standard submodule layout:
child/.git is a file containing gitdir: ../.git/modules/child, and .git/modules/child/config sets core.worktree = ../../../child`.

  1. cd child, run claude once and accept the trust dialog (claude -w refuses to start until the directory is trusted), then run claude -w and exit without making changes.
  2. "Worktree could not be removed — kept at …" appears, and git worktree list still shows the worktree.
  3. Control: cd ../../child-origin, run claude once to accept trust, then run claude -w and exit. "Worktree removed (no changes)" appears.

Note: the only difference between steps 3 and 5 is the submodule layout. Inside a submodule, git worktree list reports the main worktree as the git directory (.git/modules/child), not the checkout (parent/child).

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.300 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Git 2.54.0 (Apple Git-157). Terminal: cmux.

Installed via the Homebrew claude-code@latest cask, 2.1.300, which is the newest cask release. npm has 2.1.301, which I haven't tested.

Git itself handles this layout. In the same repro, a worktree created with plain git worktree add inside the submodule is removed by git worktree remove, whether git runs from the submodule checkout or from .git/modules/child. Inside that worktree, git rev-parse --show-toplevel returns the worktree path. The failure seems to be in Claude Code's own pre-removal checks, not in git.

Related: #27156 (claude -w repo-root detection inside a submodule), #60131 (worktree creation fails in repos with submodules), #45179 (/resume with a submodule worktree). None of them covers removal on exit.

View original on GitHub ↗