Deleted/archived sessions reappear as empty 'Session not found on disk' ghosts after desktop update

Status Fixed / completed
Reported on v2.1.209
Maintainer reply None cached
Activity 0 comments · opened Jul 18, 2026 · closed Jul 21, 2026

What happened

After a Claude Desktop app update (Windows, app version ~2.1.209 → 1.22209.0), a large number of previously deleted and archived sessions reappeared in the sidebar as empty "Session not found on disk" ghosts — each with its original title intact but no content, offering only Archive / Delete. In my case 477 of 606 sidebar entries were in this state.

Root cause (traced on disk)

The sidebar is built from per-session index stubs at:
%APPDATA%\Claude\claude-code-sessions\<guid>\<guid>\local_*.json
These stubs store only a title + config — not the conversation. The conversation lives in a transcript .jsonl under ~/.claude/projects\.

Two things combine to produce the ghosts:

  1. Transcript retention prunes transcripts but not the index stub. With the default cleanupPeriodDays (30), transcripts older than the window are auto-deleted, but the matching local_*.json sidebar stub is left behind, orphaned.
  2. "Delete" writes no tombstone. Inspecting the stubs, there is no deletedAt / archivedAt field on any entry (0 of 606). So a deleted session is only hidden from the current view; nothing on disk records that it was deleted.

When an update rebuilds the sidebar from the stub files on disk, every orphaned/deleted stub is resurfaced. They render empty ("Session not found on disk") because their transcript was pruned long ago, and some previously-archived sessions come back into the active list because the rebuild didn't re-honor isArchived.

Evidence from my machine: all ghost entries were created on/before ~July 10 (transcripts aged out); all live entries were recent (transcript still present); zero ghosts were created in the days around the update — i.e. the update didn't delete anything, it re-exposed already-orphaned stubs.

Impact

  • Sidebar becomes flooded with empty entries (hundreds), burying real sessions.
  • Users can't tell resurfaced ghosts from a genuine data-loss event without inspecting disk. It reads alarmingly like lost work.
  • Re-deleting them by hand doesn't stick across the next update, since the underlying stub persists.

Suggested fixes

  1. Write a deletion tombstone (or actually remove the local_*.json stub) when a session is deleted, so a rebuild can't resurface it.
  2. When rebuilding the sidebar, skip stubs whose transcript is missing (or garbage-collect orphaned stubs whose transcript was pruned by retention), instead of showing them as ghosts.
  3. Preserve isArchived across the rebuild.

Workaround

A stub whose transcript is missing can be safely removed (it holds no conversation) — this is what the UI "Delete" does. I scripted a dynamic sweep (match stub ids against transcripts on disk; quarantine the unmatched) to bulk-clear them, but it has to be re-run after each update because of cause #1 above.

Environment

  • OS: Windows 11
  • Claude Desktop, updating from app v2.1.209 to v1.22209.0

View original on GitHub ↗