[BUG] Session JSONL rewritten in-place to metadata-only stub — user/assistant records lost (2.1.168–2.1.170, since native installer migration)

Open 💬 3 comments Opened Jun 10, 2026 by echoplex17

Summary

Session .jsonl transcript files are being rewritten in-place to metadata-only stubs — all user/assistant message records vanish, while index-type records (ai-title, agent-name, last-prompt, mode) survive. The conversation content is permanently lost; /resume opens an empty session that still shows its title in the picker.

12 occurrences across 2 projects since migrating to the native installer on 2026-06-06. Zero occurrences before that date across ~95 older sessions in the same projects. The bug persisted across three consecutive auto-updated versions (2.1.168, 2.1.169, 2.1.170), so it does not appear version-specific within the 2.1.16x line.

This looks like a sibling of #41591 / #54907 / #39667 (those report whole-file deletion; here files survive as stubs), and possibly related to #22566 (messages silently not persisting while metadata keeps appending).

Environment

  • OS: macOS (Darwin 25.5.0)
  • Install method: native installer (~/.local/share/claude/versions/), adopted 2026-06-06 16:41 (local time)
  • Versions present: 2.1.168 (installed 06-07), 2.1.169 (06-09), 2.1.170 (06-10) — daily auto-updates
  • Projects affected: one project on an external APFS volume CWD, one in a regular home-directory CWD — so not filesystem-specific

Evidence

Scanned every *.jsonl under ~/.claude/projects/*/ and classified files with 0 user/assistant records but >0 metadata records:

project A (external volume CWD): 8/48 sessions wiped
    06-06 19:36   232 B
    06-09 18:57   360 B
    06-09 21:05   262 B
    06-09 21:06  1215 B   <- 11 metadata records, 0 messages
    06-09 21:11   135 B
    06-09 21:51   392 B
    06-10 09:16 10079 B   <- multi-hour session, 3 git commits made during it
    06-10 09:16  9577 B   <- 2-prompt session, 2 git commits made during it
project B (home dir CWD): 4/95 sessions wiped
    06-06 18:08  8930 B   <- first occurrence, ~100 min after native installer adoption
    06-07 17:54   121 B
    06-09 19:16   137 B
    06-09 21:29   131 B

All 12 are ≥ 2026-06-06 16:41. Every earlier session in both projects is intact.

Anatomy of one stub (multi-hour session, file now 9 lines):

{"type":"ai-title","aiTitle":"...","sessionId":"36bab097-..."}
{"type":"ai-title", ...}
{"type":"agent-name","agentName":"...", ...}
{"type":"ai-title", ...}
{"type":"attachment","attachment":{"type":"hook_success","hookName":"SessionStart:resume",...},"timestamp":"2026-06-10T00:16:09.403Z","entrypoint":"cli","version":"2.1.170",...}
{"type":"attachment", ... "SessionStart:resume" ...}
{"type":"last-prompt","leafUuid":"<uuid of the attachment above>", ...}
{"type":"ai-title", ...}
{"type":"mode","mode":"normal", ...}

Key forensic points:

  1. In-place rewrite, not delete/recreate: APFS birth time of the stub equals the original session start time (e.g. born 06-09 22:33, mtime 06-10 09:16), so the inode survived while content was replaced.
  2. The sessions verifiably had content: git commits were authored from inside them, and a hook-based memory plugin recorded per-turn observations live. A healthy session file from the same evening contains 86 user + 156 assistant records interleaved with the same metadata record types; the stubs contain only the metadata types.
  3. SessionStart:resume hook records are appended to the stub at the moment the user runs /resumelast-prompt.leafUuid then points at a hook attachment record, i.e. the index believes the resume attachment is the conversation tip.
  4. <session-id>/tool-results/ directories remain intact for wiped sessions (matches the "subagent/auxiliary files survive" observation in #54907).
  5. Wipe dates correlate with the daily auto-update mornings (06-07, 06-09, 06-10) plus the installer-migration day itself (06-06).

Expected

Session transcripts are append-only and never lose user/assistant records; or, if any cleanup/migration must rewrite them, it preserves message records (and backs up before rewriting).

Actual

Conversation content silently lost; stub still appears in the /resume picker with its title, opens empty. No warning, no backup, unrecoverable.

Notes

  • #41591 (canonical for the deletion variant) is closed as not planned; filing this because the truncation-to-stub variant adds new signal: inode-preserving in-place rewrite, metadata records surviving, and a clean before/after boundary at the native-installer migration.
  • Happy to provide sanitized stub files, debug logs, or run a diagnostic build.

View original on GitHub ↗

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