[Bug]: PR-status poller retries forever on a worktree folder that is no longer a git repo#24797
What happens
A thread's worktree folder can outlive its git data. The folder stays, empty, with no .git.
T3 still polls PR status for that thread. Every run fails with not_a_repository.
T3 never stops or marks the worktree missing. The same paths fail roughly every 100 s, for days.
Numbers (one self-hosted server, t3 serve 0.1.3-nightly.20261023.3566)
- 10,309
not_a_repofailures in 41 h on 7 folders, about one per folder every ~100 s. - Over the server's whole log: 34,924 such failures on the same 7 paths.
- In 110 min of trace before 08:40 CET on 2026-10-25: 6,525 PR checks (p95 5.8 s) and 19,855 git commands. The dead folders made up part of that load and all of the errors.
- All 7 folders were empty directories. Each had been dead for 3 to 5 days.
Sample log line:
| 1 | GitCommandError: Git command failed in GitManager.branchPullRequest.remotes |
| 2 | (/home/ubuntu/.t3/worktrees/<project>/t3-cfa0e066): Git command exited with a non-zero status. (not_a_repository) |
Why (source on main, commit 807319c)
- The poller runs every minute for every unsettled thread with a branch: ThreadPullRequestService.ts#L400.
- It checks only that the worktree path exists, then runs git there:
ThreadPullRequestService.ts#L188-L197.
An empty folder passes
fileSystem.exists, so T3 never falls back toproject.workspaceRoot. - The first git call is
git remotein that folder: GitManager.ts#L2511-L2518. - The failure is already classified as
not_a_repository: GitVcsDriverCore.ts#L513. Nothing acts on that result, so the next tick tries again.
Removing the empty folders makes exists false, so the fallback kicks in. That is a manual workaround, not a fix.
Ask
- Treat
not_a_repositoryfrom a thread's worktree as permanent. After N results in a row (say 3), mark the worktree missing and stop PR polling for that thread until its worktree changes. - Or check for a git worktree (a
.gitfile or folder) instead of plain path existence before choosing the worktree ascwd. - Optional: show "worktree missing" on the thread, so the user can archive it or recreate it.
Repro
- Create a thread with a worktree and a branch, and leave it unsettled.
- Delete everything inside the worktree folder, including
.git, but keep the empty folder. - Watch the server log:
not_a_repositoryfromGitManager.branchPullRequest.remotesevery poll, forever.