Sessions become unresumable after EnterWorktree → ExitWorktree, missing from both same-cwd and cross-worktree /resume pickers
Bug: Sessions become unresumable after EnterWorktree → ExitWorktree → end, in both same-cwd and cross-worktree /resume pickers
Summary
A long-running Claude Code session that used EnterWorktree to enter a worktree, then exited (via /exit or end-of-turn) without the harness fully clearing the worktree binding, becomes invisible in /resume — both in the default same-cwd picker and in the cross-worktree "show other worktrees" picker. The only way to recover the session is to know the session UUID and pass it to claude --resume <uuid> directly.
Reproduction was observed on Windows. The session held active work that the user could not get back to via the normal resume UI.
Environment
- OS: Windows 10 Pro 10.0.19045
- Shell: PowerShell + Git Bash
- Claude Code: Opus 4.7 (1M context),
claude-opus-4-7[1m] - Multiple concurrent Claude Code processes running against the same project, in different terminals/worktrees
(Paths in this report are redacted as <HOME>, <PROJECT>, <WT_A>, <WT_B>, etc.)
Symptoms
- User runs
/resumefrom the original project cwd (<HOME>\project\<PROJECT>). - The picker shows some sessions but omits the specific session the user actually wants to resume (a session that was last active <1h ago, in the same project).
- User tries the cross-worktree resume option ("show sessions from other worktrees"). The missing session is still not listed.
- Direct invocation works:
claude --resume <full-uuid>recovers the session cleanly.
Root cause analysis
I inspected the session jsonl at:
~/.claude/projects/<project-slug>/<sid>.jsonl
Findings:
- Session lifecycle: ~7 days old, last activity earlier today. 5,320 entries, 11 MB, 287
worktree-stateevents (heavy EnterWorktree usage throughout). - First
cwd: the project root → so the session is indexed under the project root slug, not under any worktree-specific slug. cwddistribution within the session (top entries):<HOME>\project\<PROJECT>\.claude\worktrees\<WT_A>— 838 entries<HOME>\project\<PROJECT>— 672 entries<HOME>\project\<PROJECT>\.claude\worktrees\<WT_B>— 371 entries- …(~17 more cwds, mostly worktrees)
- Last
worktree-stateevents (in order):
``json`
// line 5304
{ "worktreePath": "...\\<WT_A>", "enteredExisting": true, ... }
// line 5310
null
// line 5314
null
null
So the harness *did* emit two trailing worktree-state events, presumably from ExitWorktree. But the session still does not appear in either /resume` view from the project root.
- Last user-issued command before unresumability:
/resume(which itself printedThis conversation is from a different directory. To resume, run: cd '<root>' && claude --resume <other-sid>for a different session — i.e. the picker thought the current session belonged to a different directory than where the user actually was), then/exit, whose local-command-stdout was:
````
Returned to <HOME>\project\<PROJECT> (worktree at <HOME>\project\<PROJECT>\.claude\worktrees\<WT_A> left in place)
Hypothesis
The resume picker appears to filter candidates using a combination of:
- The session's index folder (= the slug derived from the first cwd).
- The latest
worktree-statevalue in the session's jsonl. - Possibly the current cwd of the invoking
claudeprocess.
When the latest worktree-state does not cleanly match the invoking cwd (or has a non-null worktree binding that is stale because the harness didn't roll it back, or has null-but-with-a-prior-non-null-active-worktree that the picker treats as "still in a worktree"), the session is dropped from both pickers:
- Same-cwd picker: rejects because "session belongs to a different directory".
- Cross-worktree picker: rejects because the worktree state doesn't match any known worktree (maybe the worktree was already removed at the OS level, but
worktree-statestill references it).
This is consistent with the "worktree at … left in place" line — the harness left the worktree on disk but the session metadata is in an in-between state.
Steps to reproduce (best guess)
- Start a long-running Claude Code session in the project root.
- Use
EnterWorktree(orcdinto an existing worktree) multiple times across the session, hopping between worktrees. - In one of the worktrees, use a sub-agent that itself enters/exits the worktree (sidechain).
- Toward the end, run
/resume(which lists other sessions, not the current one), then/exit. - Open a new
claudefrom the project root → run/resume. The just-ended session is missing. - Toggle the cross-worktree picker option. Still missing.
claude --resume <known-uuid>works.
I have not yet constructed a minimal repro outside this real session; happy to try if you point me at what state to inspect.
Workaround
Pass the session UUID directly: claude --resume <uuid>. The UUID can be recovered by listing ~/.claude/projects/<project-slug>/*.jsonl by modification time.
Suggested fix directions
- The resume picker should fall back to any session whose index folder matches the project root, regardless of trailing
worktree-state, when the user explicitly toggles "show all sessions for this project". - Or: when
worktree-stateisnullat the tail of the file, treat the session as belonging to its index-folder cwd, not to the last non-nullworktree-state. - Or: list the session under both the project root and any worktree it touched during its lifetime, so the cross-worktree picker can find it.
Privacy note
Paths, project names, and worktree names have been redacted. I can share a redacted excerpt of the offending jsonl on request.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗