Worktree-relocated background agent sessions crash-loop on reopen from the agents view ("No conversation found with session ID")
Background agent sessions relocated into a git worktree crash-loop on reopen from the agents view ("No conversation found with session ID")
Summary
Opening certain entries from the agents view crashes the worker repeatedly with:
No conversation found with session ID: <uuid>
[worker crashed (exit 1) — respawning…]
The worker respawns ~4 times, then gives up and drops back to the agents view. The broken entry stays in the list — it is not dismissed by the crash and only disappears after Ctrl-X. I've hit this at least 5 times across sessions.
Root cause is a path/cwd mismatch for background sessions that were relocated into a git worktree: the conversation transcript is stored under the worktree's encoded project directory, but the background job that the agents view lists records cwd/originCwd as the parent repository. On reopen, the worker is launched with cwd = parent repo and resumes by explicit session ID; the conversation set it loads is scoped to the parent-repo project and does not contain the worktree transcript, so the explicit-ID lookup fails (failure_reason: "not_found_explicit_id") and the worker calls process.exit(1).
This is closely related to #5768 (resume only works from the directory where the session was started) — it's a specific, crash-looping instance of that cwd-keyed-resume family — and adjacent to #57920 (worktree transcript not found on --resume), but distinct: the worktree here is live (not removed), and the failure surfaces via the agents view with a worker crash/respawn loop rather than a one-shot CLI error.
Environment
- Claude Code 2.1.162 (macOS)
- The affected job record was created under 2.1.161; the bug still reproduces on 2.1.162.
- Sessions were relocated into git worktrees under
<repo>/.claude/worktrees/<branch>/(a worktree-per-task workflow).
Steps to reproduce
- From a repo root (e.g.
/Users/USER/dev/myrepo), launch/spawn a background agent session. - During that session, relocate it into a git worktree (e.g.
/Users/USER/dev/myrepo/.claude/worktrees/<branch>/). The transcript is now written under the project directory encoded from the worktree path. - Let the job reach a terminal state (
state: "done"). - Later, from the agents view, select that session to reopen it.
Expected: the conversation resumes (the transcript exists and is valid).
Actual: No conversation found with session ID: <uuid> → [worker crashed (exit 1) — respawning…], repeated ~4× before returning to the agents view. The entry persists in the list until removed with Ctrl-X.
Evidence / diagnosis
For one crashing session (<uuid>):
The transcript exists and is valid — only under the worktree-encoded project dir:
$ find ~/.claude/projects -name '<uuid>.jsonl'
~/.claude/projects/-Users-USER-dev-myrepo--claude-worktrees-<branch>/<uuid>.jsonl # valid, hundreds of lines
# NOT present under the parent-repo project dir, which is where a cwd-scoped lookup searches:
$ ls ~/.claude/projects/-Users-USER-dev-myrepo/<uuid>.jsonl
No such file or directory
Note the -- in myrepo--claude-worktrees: the project-dir encoding maps both / and . to -, so /myrepo/.claude/worktrees → -myrepo--claude-worktrees. The worktree itself is live — git worktree list shows the branch checked out there. This is not a deleted-worktree problem.
The job record that backs the agents-view entry — ~/.claude/jobs/<jobid>/state.json — has the mismatch:
{
"state": "done",
"resumeSessionId": "<uuid>",
"linkScanPath": "/Users/USER/.claude/projects/-Users-USER-dev-myrepo--claude-worktrees-<branch>/<uuid>.jsonl",
"cwd": "/Users/USER/dev/myrepo", // parent repo, NOT the worktree
"originCwd": "/Users/USER/dev/myrepo",
"cliVersion": "2.1.161"
}
The job already stores the correct transcript location in linkScanPath, but cwd/originCwd point at the parent repo. The resume path keys off cwd + explicit session ID, not linkScanPath.
The failing code path (from the bundle; 2.1.160/2.1.161 shown, logic unchanged in 2.1.162):
{entrypoint:"cli_flag", success:!1, failure_reason:"not_found_explicit_id"});
let rT = `No conversation found with session ID: ${id}`;
return V(rT,{level:"error"}), await exit1Fn(); // exit1Fn === process.exit(1)
exit(1) is the "worker crashed (exit 1)"; the supervisor respawns, re-attempts the same explicit ID against the same (wrong) cwd-scoped conversation set, and exits 1 again — producing the bounded respawn loop.
This is a class, not a one-off. Scanning all background jobs with a state.json, multiple carry the same signature (transcript/linkScanPath under a *worktrees* project dir while cwd/originCwd is the parent repo). I've personally had to Ctrl-X / kill at least 5 such entries across sessions.
Two observations bundled here
- The crash loop on reopen (primary): cwd-scoped explicit-ID resume can't find a transcript that lives under the worktree project dir.
- The entry isn't dismissed by the crash — it persists in the agents view because it is a
state: "done"job directory at~/.claude/jobs/<jobid>/; the crash doesn't update or remove that backing record, so onlyCtrl-Xclears it. Arguably the worker should notexit(1)(taking down the TUI worker) on a recoverable "conversation not found" — it should surface a non-fatal error and leave the agents view responsive.
Suggested fixes (any one breaks the loop)
- On resume, resolve the conversation from the job's
linkScanPath(or search across all project dirs by session ID) instead of only the cwd-derived project dir; or record the worktree path as the job'scwd/originCwdwhen the session is relocated into a worktree, so respawn launches the worker in the directory whose project dir holds the transcript. - Make "conversation not found" non-fatal in the worker: show an error and return to the agents view instead of
process.exit(1)+ respawn. This caps the blast radius even if the lookup still misses. - When a reopen permanently fails, mark/prune the agents-view entry so the user isn't forced to
Ctrl-Xevery stale row.
Workaround (for affected users)
The transcript is intact; only the resume path is broken. Re-launching claude from inside the worktree directory itself (so cwd matches the transcript's project dir) and resuming by ID works. The crash itself is harmless — it can't corrupt the transcript — but the entry must be cleared from the agents view with Ctrl-X.
Related
- #5768 — resume only works from the directory where the session was started (the underlying cwd-keyed-resume family).
- #57920 — worktree transcript not found on
--resumeafter the worktree path is removed (similar mechanism; that one requires the dir to be removed and has no crash loop / agents-view surface). - #60106 — agents-view orphans a session via clear(new)/clear(reset) (agents-view-orphan surface, no worktree, no crash loop).
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗