Steps to reproduce
Deterministic, without any AI provider involved:
- Open any git repository as a T3 Code project (WSL runtime).
- On the host, simulate a held config lock:
touch <repo>/.git/config.lock (any pre-existing file works; git's config writer uses O_CREAT|O_EXCL on that path).
- Create a new thread with a worktree.
How it actually happens in practice (no manual touch): Claude Code's Linux/WSL sandbox deny-writes <main-repo>/.git/config.lock with a bubblewrap bind mount and materializes a 0-byte, mode 0444 placeholder on the host for the duration of every sandboxed Bash command, in the main repo's .git even when the thread runs in a linked worktree (anthropics/claude-code#78818, confirmed by a maintainer). Any T3 worktree creation that overlaps a Bash command in another thread hits step 2 for free, and the provider chosen for the new thread is irrelevant: my last failure was a Codex thread, created while a Claude thread in another worktree was 5 minutes into a 7-minute test run. With three busy threads I got 7 failures in one afternoon.
Expected behavior
Either of:
createWorktree treats git config branch.<new>.gh-merge-base <base> as best-effort: log a warning, keep the worktree, let the thread start (the merge base can be re-derived later, resolveBaseBranchForNoUpstream already falls back to the default branch).
- Or, if the config write is required, roll back the
git worktree add and the branch so no orphan is left behind, and retry the config write a few times (the lock is transient by nature).
Also: surface git's stderr in the error (#4380). "Git command exited with a non-zero status." hid a one-line could not lock config file .git/config: File exists that would have made the diagnosis trivial.
Actual behavior
GitVcsDriver.createWorktree runs git worktree add -b <new> <path> <ref> (succeeds), then git config branch.<new>.gh-merge-base <base> in the main repo, which exits 255. The whole command fails with:
Git command failed in GitVcsDriver.createWorktree.configureBaseRef (/home/eran/batalyse/batalyse): Git command exited with a non-zero status.
The thread is never created, but the worktree directory under ~/.t3/worktrees/<repo>/t3code-<id> and the branch t3code/<id> remain. I had to clean up 4 orphans by hand (git worktree remove + git branch -D); nothing in the UI shows them.
How bad is this in practice?
Major degradation or frequent failure
Version or commit
T3 Code (Alpha) 0.0.40, WSL runtime sha256-02c38816d0b6722af4ec74c48982ab009586fe7f84274cc757fe8f039c4784db
Environment
Windows 11 desktop app, WSL2 Ubuntu (kernel 6.18.33.2-microsoft-standard-WSL2), git 2.53.0, Claude Code 2.1.270 as provider with the sandbox enabled
Logs or stack traces
{"type":"effect-span","name":"createWorktree","durationMs":1241.5,"exit":{"_tag":"Failure","cause":"GitCommandError: Git command failed in GitVcsDriver.createWorktree.configureBaseRef (/home/eran/batalyse/batalyse): Git command exited with a non-zero status.\n at createWorktree (file:///home/eran/.t3/wsl-runtime/sha256-02c38816.../apps/server/dist/bin.mjs:83455:66)\n at createWorktree (definition) (file:///home/eran/.t3/wsl-runtime/sha256-02c38816.../apps/server/dist/bin.mjs:83128:25)"}}
{"type":"effect-span","name":"GitVcsDriver.createWorktree","durationMs":1216.7,"attributes":{"git.operation":"GitVcsDriver.createWorktree","git.cwd":"/home/eran/batalyse/batalyse","git.args_count":6},"exit":{"_tag":"Success"}}
{"type":"effect-span","name":"GitVcsDriver.createWorktree.configureBaseRef","durationMs":10.8,"attributes":{"git.operation":"GitVcsDriver.createWorktree.configureBaseRef","git.cwd":"/home/eran/batalyse/batalyse","git.args_count":3},"exit":{"_tag":"Success"}}
(The last span reads Success because executeGit runs with allowNonZeroExit: true and checks the exit code outside the span, so the trace never records the failing exit code or stderr.)
Reproduced by hand on the host while the placeholder existed:
$ git config branch.zz-probe.gh-merge-base main; echo exit=$?
error: could not lock config file .git/config: File exists
exit=255
$ ls -la .git/config.lock
-r--r--r-- 1 eran eran 0 Sep 14 13:21 .git/config.lock
Workaround
Delete the stale <repo>/.git/config.lock when it is a 0-byte 0444 file (a bubblewrap placeholder, not a git lock), create the worktree while no other thread is running a Bash command, and remove orphans with git worktree remove <path> && git branch -D t3code/<id>.
Steps to reproduce
Deterministic, without any AI provider involved:
touch <repo>/.git/config.lock(any pre-existing file works; git's config writer usesO_CREAT|O_EXCLon that path).How it actually happens in practice (no manual
touch): Claude Code's Linux/WSL sandbox deny-writes<main-repo>/.git/config.lockwith a bubblewrap bind mount and materializes a 0-byte, mode 0444 placeholder on the host for the duration of every sandboxed Bash command, in the main repo's.giteven when the thread runs in a linked worktree (anthropics/claude-code#78818, confirmed by a maintainer). Any T3 worktree creation that overlaps a Bash command in another thread hits step 2 for free, and the provider chosen for the new thread is irrelevant: my last failure was a Codex thread, created while a Claude thread in another worktree was 5 minutes into a 7-minute test run. With three busy threads I got 7 failures in one afternoon.Expected behavior
Either of:
createWorktreetreatsgit config branch.<new>.gh-merge-base <base>as best-effort: log a warning, keep the worktree, let the thread start (the merge base can be re-derived later,resolveBaseBranchForNoUpstreamalready falls back to the default branch).git worktree addand the branch so no orphan is left behind, and retry the config write a few times (the lock is transient by nature).Also: surface git's stderr in the error (#4380). "Git command exited with a non-zero status." hid a one-line
could not lock config file .git/config: File existsthat would have made the diagnosis trivial.Actual behavior
GitVcsDriver.createWorktreerunsgit worktree add -b <new> <path> <ref>(succeeds), thengit config branch.<new>.gh-merge-base <base>in the main repo, which exits 255. The whole command fails with:The thread is never created, but the worktree directory under
~/.t3/worktrees/<repo>/t3code-<id>and the brancht3code/<id>remain. I had to clean up 4 orphans by hand (git worktree remove+git branch -D); nothing in the UI shows them.How bad is this in practice?
Major degradation or frequent failure
Version or commit
T3 Code (Alpha) 0.0.40, WSL runtime
sha256-02c38816d0b6722af4ec74c48982ab009586fe7f84274cc757fe8f039c4784dbEnvironment
Windows 11 desktop app, WSL2 Ubuntu (kernel 6.18.33.2-microsoft-standard-WSL2), git 2.53.0, Claude Code 2.1.270 as provider with the sandbox enabled
Logs or stack traces
(The last span reads
SuccessbecauseexecuteGitruns withallowNonZeroExit: trueand checks the exit code outside the span, so the trace never records the failing exit code or stderr.)Reproduced by hand on the host while the placeholder existed:
Workaround
Delete the stale
<repo>/.git/config.lockwhen it is a 0-byte 0444 file (a bubblewrap placeholder, not a git lock), create the worktree while no other thread is running a Bash command, and remove orphans withgit worktree remove <path> && git branch -D t3code/<id>.