Internal GC silently deletes non-empty session JSONL during active conversation

Resolved 💬 3 comments Opened Mar 23, 2026 by zzkevin2019 Closed Mar 27, 2026

Summary

During an active Claude Code session, an internal garbage-collection routine silently deleted a non-empty session JSONL file (1.67 MB, 31 user messages) along with 21 other files. The file was not moved to Trash — it was hard-deleted and only recoverable via Dropbox version history.

Environment

  • Claude Code version: 2.1.81
  • OS: macOS (Darwin 25.3.0, MDT / UTC-6)
  • Shell: zsh

Timeline (all times local MDT, 2026-03-22)

| Time | Event |
|------|-------|
| 21:34 | SessionEnd backup hook runs — rsync --delete finds all files intact |
| 22:08 | New session starts via claude -r |
| ~22:09 | Python script successfully reads fdb7be36...jsonl (1.67 MB) from ~/.claude/projects/ |
| 22:21 | iCloud backup hook runs — rsync --delete discovers files already gone from source, deletes from backup |
| 22:35 | Dropbox backup hook runs — same; Dropbox records 22 files deleted |

The file disappeared from ~/.claude/ in a ~12-minute window between a successful read and the next backup run, during an active session where no write/delete commands were issued.

Deleted files (22 total, all at same timestamp)

Recovered from Dropbox's deleted-files log:

Session JONLs (the bug):

  • fdb7be36-4cec-4342-a0fa-3b0e9721a34d.jsonl — 1.67 MB, 31 user messages per session-meta. A completed session from Feb 19-20.
  • 6ce739c7-10c6-4817-9733-4c32c698e23a.jsonl — 241.82 KB

Debug logs (~/.claude/debug/*.txt): 11 files with UUID names (228 B to 257 KB)

Settings backups: 4 .claude.json.backup.<epoch> files (27 KB each, from that afternoon)

Empty session directories: 4fd14dc1..., 82088d17...

PID file: 54086.json (138 B)

The batch deletion of heterogeneous file types (debug logs, session transcripts, settings backups, PID files) at the same instant suggests a single internal cleanup routine.

What was ruled out

  • User commands: Every bash command in the session was read-only (verified by extracting all tool calls from the session JSONL).
  • Hooks: The user's SessionEnd hooks only run rsync backups. PreCompact hooks only copy/export. No hook deletes session JONLs.
  • /clean-sessions skill: Only targets sessions with 0 user messages and moves to ~/.Trash/. This session had 31 messages and was not found in Trash.
  • Claude Code update: No update occurred on 3/22 (versions: 2.1.79 on 3/18, 2.1.80 on 3/19, 2.1.81 on 3/20).
  • Other Claude process: Another claude -r process was running in the same project, but lsof showed no JSONL files open.

Impact

  • Silent data loss of a session transcript with no warning or log entry
  • Hard delete (not moved to ~/.Trash/), making recovery dependent on third-party backup services
  • The deleted session's subdirectory (subagents/) was preserved, leaving orphaned data

Expected behavior

  • Non-empty session JONLs should never be silently deleted
  • Any cleanup routine should log what it deletes (e.g., to the debug log)
  • Deleted session files should be moved to Trash, not hard-deleted, consistent with how /clean-sessions handles empty sessions

Reproduction

Not deterministic. The affected session was ~1 month old (Feb 19-20) and had been idle since. The deletion occurred shortly after starting a new session in the same project via claude -r.

View original on GitHub ↗

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