Worktree-relocated background agent sessions crash-loop on reopen from the agents view ("No conversation found with session ID")

Open 💬 3 comments Opened Jun 3, 2026 by SynVisions

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

  1. From a repo root (e.g. /Users/USER/dev/myrepo), launch/spawn a background agent session.
  2. 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.
  3. Let the job reach a terminal state (state: "done").
  4. 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 livegit 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

  1. The crash loop on reopen (primary): cwd-scoped explicit-ID resume can't find a transcript that lives under the worktree project dir.
  2. 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 only Ctrl-X clears it. Arguably the worker should not exit(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's cwd/originCwd when 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-X every 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 --resume after 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).

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗