[BUG] Worktree/chip spawn fails in git-submodule repos: 'Background full checkout failed: other' (extensions.worktreeConfig arms inherited core.worktree)

Open 💬 0 comments Opened Jul 5, 2026 by Narib777

Summary

Starting a worktree session (or clicking a background-task chip) in a project that is itself a git submodule fails with "Background full checkout failed: other". Every git command inside the freshly created worktree dies with:

fatal: cannot chdir to '../../../../../../path/to/super/Projects/<submodule>': No such file or directory

after which the app removes the orphaned worktree and the session never starts.

Environment

  • Claude Desktop (macOS, Darwin 25.5), Claude Code binary 2.1.197
  • git 2.x (reproduced on the stock Apple git and Homebrew git)
  • Project root = an absorbed submodule of a super-repo (its .git is a gitfile pointing at <super>/.git/modules/<sub>; the module's --local config carries the standard relative core.worktree)

Mechanism (established by controlled experiment, not inference)

The lethal state requires both of these on the submodule's shared (--local) config:

| state | --local core.worktree | extensions.worktreeConfig | in-worktree git |
|---|---|---|---|
| (a) raw absorbed submodule | set | off | works (relative path resolved from the common gitdir) |
| (b) armed | set | true | breaksfatal: cannot chdir (exit 128) |
| (c) healed | unset (moved to main worktree's config.worktree) | true | works |

With extensions.worktreeConfig=true, git resolves the shared relative core.worktree from each linked worktree's own gitdir (.git/modules/<sub>/worktrees/<name> — two levels deeper than the module gitdir the path was written for) → nonexistent path → every command fails. This is the documented git requirement: enabling worktreeConfig obliges relocating core.worktree into the main worktree's config.worktree (git-worktree(1) CONFIGURATION FILE section). The app enables the extension but never relocates core.worktree.

Why the app arms its own landmine (one-success-then-break)

From ~/Library/Logs/Claude/main.log, the worktree setup runs git config extensions.worktreeConfig true (and git config --worktree core.longpaths true) after checkout:

  1. First spawn on a raw submodule (state a): succeeds — and its setup writes extensions.worktreeConfig=true into the submodule's shared config → repo is now state (b).
  2. Every subsequent spawn fails — the first in-worktree command (git ls-tree --name-only HEAD -- CLAUDE.md ...) dies with cannot chdir, and the recovery commands (git config extensions.worktreeConfig true, git config --worktree core.longpaths true) fail with the same error because they also run with cwd inside the broken worktree (chicken-and-egg).

Observed exactly as a 12:46 success followed by a 13:49 failure in the same repo, and reproduced deterministically.

Additional trap: even after a manual heal (state c), any git submodule update --init re-adds --local core.worktree (git re-writes it for absorbed submodules) → repo returns to state (b) and chips break again. So a one-shot fix on the app side must be re-checked at every worktree spawn.

Minimal repro

# super repo with one absorbed submodule "sub"
git init super && cd super
git submodule add <any-repo-url> sub
git commit -m "add sub"

cd sub
git worktree add .claude/worktrees/t1 HEAD --detach
git -C .claude/worktrees/t1 status                  # works (state a)
git worktree remove --force .claude/worktrees/t1

git config extensions.worktreeConfig true           # what the app's worktree setup does
git worktree add .claude/worktrees/t2 HEAD --detach
git -C .claude/worktrees/t2 status                  # fatal: cannot chdir ... (state b)

Suggested fix

In the worktree-creation path, when the base repo's --local config contains core.worktree (i.e. the base is an absorbed submodule), run against the base repo, before git worktree add (not from inside the new worktree):

cw=$(git config --local core.worktree)          # non-empty → absorbed submodule
git config extensions.worktreeConfig true
git config --worktree core.worktree "$cw"       # relocate to the MAIN worktree's config.worktree
git config --local --unset core.worktree

and re-check on every spawn (because git submodule update re-adds the --local value). Verified: this takes the repo to state (c), where both the main checkout and all linked worktrees work.

Related

Adjacent submodule/worktree family, different failure signatures: #54904 (not-a-git-repo, repo containing submodules), #55387, #60131, #27156.

View original on GitHub ↗