Desktop app: sessions that ran in a git worktree can't be resumed after restart — app silently rebinds the conversation to a new empty session, orphaning the transcript
Status Fixed / completed
Reported on v2.1.219
Maintainer reply None cached
Workaround ✓ Mentioned in description ↑
Activity 3 comments · opened Aug 3, 2026 · closed Aug 25, 2026
Environment
- Claude desktop app 1.24012.9 (macOS, Darwin 25.3.0, arm64)
- Bundled Claude Code engine 2.1.219 (transcript stores also touched by standalone CLI 2.1.220)
Summary
Transcripts for sessions that work inside a git worktree (.claude/worktrees/<name>) are filed under a worktree-derived project key in ~/.claude/projects/, but the desktop app resolves a conversation's transcript from the window folder's key. The mismatch is invisible while the engine process is alive. On the first resume after the engine dies (e.g. app relaunch):
- The send fails with
No conversation found with session ID: <id>. - A banner appears: "Session history unavailable — this session's conversation history is no longer on disk."
- If the user presses Try again / Start fresh / re-sends, the app silently rebinds the conversation record's
cliSessionIdto a brand-new empty session. The original transcript is never deleted — just orphaned — but from the user's perspective, weeks of context vanish with no way back in-app.
Reproduction
- In the desktop app, start a conversation in folder
F; have the session do its work inside a git worktree (fork-with-worktree, orEnterWorktree). - Quit the app (engine process dies).
- Reopen, open that conversation, send any message.
- Observe the error; press Try again → conversation is now bound to a fresh empty session. The real transcript still sits at
~/.claude/projects/<key-derived-from-worktree-path>/<old-id>.jsonl.
Evidence from an affected machine
- App record
~/Library/Application Support/Claude/claude-code-sessions/<acct>/<org>/local_<uuid>.jsonshowedcliSessionIdchanged from the original id to a fresh one after retry;cwd= window folder. - Original transcript intact (32 MB, 7,167 lines) under
-<...>-<repo>--claude-worktrees-<name>/. - The fresh stub jsonl begins with a
queue-operationenqueue of the exact retried user message. - 11 worktree-keyed transcript folders on this machine: every historical worktree session shares the latent condition; only the ones the user tried to resume broke. Two long-running conversations were lost the same afternoon this way.
Expected behavior
- Transcript resolution should follow the transcript (also search worktree-derived keys, or re-home the file to the origin key on worktree entry/exit or session end).
- The app should never silently rebind a titled conversation to an empty session. At minimum, preserve the previous
cliSessionIdin the record so in-app recovery stays possible.
Manual workaround (verified, lossless)
Stop the stub's engine process, rewrite the orphaned jsonl's top-level sessionId fields to the newly-bound stub id, place it at the stub's path, copy the session's sidecar dir (subagents/, tool-results/), restart the app. Full history returns.
Possibly related: #33912 (CLI --resume returns "No conversation found" with files present; closed).
3 Comments
Confirming an independent reproduction, 2026-08-11, macOS (Darwin 25.5.0, arm64), desktop app with embedded Agent SDK 0.3.222, model claude-fable-5.
Sequence observed:
EnterWorktreeand did its work there (worktree at<repo>/.claude/worktrees/feat+sy448-normal-twin-collection-mirror).~/.claude/projects/-Users-…-Pokemon-Go-Collection-Tracker--claude-worktrees-feat-sy448-normal-twin-collection-mirror/f70def20-86ad-4293-be7b-8fb1ec65e2ca.jsonl(844 KB, intact, plus its<session-id>/subagents/sidecar dir).git worktree remove); the transcript stayed put under the worktree key.No conversation found with session ID: f70def20-86ad-4293-be7b-8fb1ec65e2caon send.~/Library/Application Support/Claude/claude-code-sessions/<acct>/<org>/local_<uuid>.jsonnow showscliSessionId: b915f0c7-…(the new stub) withcwd= the main checkout, while the original transcript sits untouched under the worktree key.Two details worth adding to the record:
cleanupPeriodDayswas set to 3650 on this machine, ruling out retention cleanup — the failure is purely key resolution, matching the report's analysis.+1 to the expected behavior as stated: resolve transcripts by session id across project keys (it's a UUID — unique), or re-home the transcript to the origin key on worktree exit / session end, and never silently rebind a titled conversation to an empty session without preserving the previous
cliSessionId.The original transcript is still present, and the empty Desktop session is the new stub. Preserve that file before pressing Try again or Start fresh. I have seen worktree sessions get split this way: the transcript sits under the worktree-derived project slug while Desktop looks under the window-folder slug after restart.
Run
python tools/diagnose.pybefore sending another message. It will compare the metadatacliSessionId,cwd, and the transcript project slug, then print the exact next command if it recognises a path mismatch. Run the printed command in dry-run mode first; fully quit Desktop before any apply step and keep the original transcript plussubagents/andtool-results/sidecars backed up.I built
BasedGPT/claude-code-session-recoverywith the session-path diagnostics and repair route for one project being represented by multiple project slugs. In this case, do not rewrite the transcript's ids by hand unless the diagnostic points you there; the important distinction is an intact transcript under the worktree key versus a genuinely missing transcript. The 3650-day retention setting also makes ordinary cleanup less likely, so the project-key lookup is the first thing to check.Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.