[BUG] Claude Code transcripts loss
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code: CLI transcripts silently disappear from ~/.claude/projects/, and sidebar stubs self-destruct on click
Related but distinct: #29373, #29154, #29172 are all about update-triggered sidebar loss. This report is about an ongoing, post-update failure mode (the jsonls keep disappearing) plus a separate stub-corruption step not covered in those issues.
Environment
- macOS: 26.4 (25E246)
- Claude Desktop: 1.3109.0
- Claude Code CLI bundled: 2.1.111
- Setup: two Claude accounts used on the same Mac, signed in/out frequently to switch between work contexts. Not confirmed this is required to trigger the bug, just describing my setup.
Summary
Two interacting bugs cause silent loss of historical Claude Code sessions:
- Main
<sessionId>.jsonltranscripts under~/.claude/projects/<encoded-cwd>/disappear over time. I don't know the exact trigger — only the correlates described below. - When the user clicks a sidebar thread whose transcript is missing, the app wipes the stub's
cliSessionIdon disk, making manual recovery (e.g. from Time Machine) much harder.
Bug 1 — Transcripts disappear from ~/.claude/projects/
~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl files are missing for many older threads, even though the sidebar stubs (~/Library/Application Support/Claude/claude-code-sessions/<org>/<workspace>/local_*.json) for those threads still exist. Clicking such a stub shows "No messages yet".
Oddly, the subagent traces under ~/.claude/projects/<encoded-cwd>/<sessionId>/subagents/ are left intact — only the main <sessionId>.jsonl and its enclosing per-session directory are gone. So you end up with orphaned subagents/ dirs next to the index, with no main transcript.
What I can say about the trigger: I don't know for sure. The Claude.ai desktop log (~/Library/Logs/Claude/main.log) records 155 [growthbook] refreshing for account change events between the last real activity of one of my lost threads (2026-03-17) and the first Transcript … no longer exists, starting fresh log line for it (2026-04-15). That's highly suggestive, but also a period over which the app was quit/relaunched and updated many times, so account switching is only one of several possible culprits. A re-loss I observed today happened about 10 minutes after an app quit, with no account change in between — so quit/restart cycles alone seem sufficient to reproduce at least some of the reaping.
Bug 2 — Stub self-destructs on click when transcript is missing
When a user clicks a sidebar thread whose transcript was reaped, the log shows:
[CCD] Transcript for <sessionId> no longer exists, starting fresh
The app then wipes the stub's cliSessionId field on disk so it can "start fresh". Even if the transcript file is then restored manually, the stub no longer points to it, and the sidebar still shows "No messages yet". Worse, the wiped state is cached in memory, so subsequent focus events re-write the wiped stub back to disk — clobbering any manual repair until the app is quit and relaunched.
Reproduction
Bug 1 (transcript disappearance — partial, not fully controlled)
I don't have a deterministic repro. What I can say:
- After extended normal use of Claude Desktop + Claude Code over weeks/months (with frequent quits, relaunches, desktop updates, and account switches), many older
<sessionId>.jsonlfiles under~/.claude/projects/are gone while their sidebar stubs remain. - Today I recovered two such jsonls from Time Machine and copied them back into the project directory. They were reaped again within a couple of hours — about 10 minutes after an app quit/relaunch, with no account change in between.
Bug 2 (stub self-destructs on click — fully reproducible, seen live today)
- Arrange for a broken stub: sidebar entry exists, but its
cliSessionIdpoints to a missing.jsonlunder~/.claude/projects/<encoded-cwd>/. - Click the entry in the sidebar.
- Observe in
~/Library/Logs/Claude/main.log:
````
[CCD] Transcript for <sessionId> no longer exists, starting fresh
- Observe in the stub file on disk:
cliSessionIdis nownull. - Manually rewrite the stub to restore
cliSessionId. Click the entry again without quitting the app. The app re-saves the stub withcliSessionId: null, clobbering the fix (in-memory cached state overwriting disk). Only quitting and relaunching the app breaks that cycle.
This is reproducible on demand — I reproduced it multiple times today while testing a recovery script.
Impact
- Users lose CLI transcripts silently. No warning, no recovery UI.
- Sidebar entries remain, so the loss isn't visible until a thread is clicked.
- Manual recovery (e.g. from Time Machine) is possible but fragile: the reaping recurs, and Bug 2 makes each recovery attempt harder than it needs to be.
Suggested fixes
- Whatever is pruning
~/.claude/projects/during quit/restart/account-change, stop pruning transcripts that still have a valid sidebar stub referring to them. At the very least, never remove a<sessionId>.jsonlwhen a stub anywhere on the machine has a matchingcliSessionId. - When
"Transcript no longer exists, starting fresh"fires, do not wipecliSessionId. If the user chooses to continue the session, a fresh sessionId gets created anyway. Wiping the existing one makes Time-Machine-style recovery much harder. - Surface a warning ("Transcript for this thread wasn't found — start fresh, or cancel to investigate?") rather than silently mutating state.
- Bonus: a "where did my history go?" diagnostic / recovery tool. Given how many overlapping closed issues there are about sidebar-vs-disk mismatches (#29373, #29154, #29172), a built-in "rescan
~/.claude/projects/and rebuild sidebar stubs" command would save users a lot of manual forensics.
Workaround I've been using
I wrote a small Python script that:
- reads
~/Library/Application Support/Claude/claude-code-sessions/<org>/<workspace>/local_*.jsonstubs, - finds broken ones (no
cliSessionId, or pointing to a missing jsonl), - matches them against recovered jsonls (from Time Machine) by sessionId or by cwd+firstPrompt,
- copies jsonls into
~/.claude/projects/<encoded-cwd>/, - writes a fresh
sessions-index.json, - patches the stub to restore
cliSessionId.
Happy to share if helpful for building a first-party recovery tool.
What Should Happen?
Transcripts shouldn't get lost...
Error Messages/Logs
Steps to Reproduce
See above
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.111 (CLI) 1.3109.0 (Desktop)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗