JSONL transcript corruption: phantom parentUuid on first message after resume (v2.1.146, Opus 4.7)
Summary
After --resume of a session that previously had /compact applied, the first user prompt and several subsequent ones write to the JSONL with a parentUuid that points to a UUID never written to disk — a phantom reference held only in the previous process's RAM. The chain lastEntry → … → phantom breaks, and Claude's own backtrace on the next --resume truncates history.
This is symptomatically the same as #21617 / #22526 / #24304 / #21751 / #36583 but with a distinct trigger pattern that does not appear in those threads:
- Not
file-history-snapshotcollision (I havefileCheckpointingEnabled: false) - Not subagent
prompt_suggestiontext-block split (verified: no matching UUIDs inagent-*.jsonl) - Not missing-newline write race (no concatenated JSON on the affected lines)
Trigger appears to be resume-time RAM-to-disk discontinuity: the first user prompt after claude --resume references a parentUuid that exists in the resuming process's session state but was never serialized to JSONL.
Repro
- Start a session, do work
- Run
/compact(manual) - Type a prompt → see Claude respond fully
- Exit (Ctrl+C×2 OR close terminal OR system shutdown — multiple variants tested)
claude --resume <session-id>- Type the next prompt
The next user-message entry in the JSONL has parentUuid pointing to a UUID nowhere in the file.
Observed in production session
L2089 13:48:32 system/compact_boundary uuid=61f8085a parentUuid=null
L2090 13:48:32 user(isCompactSummary) uuid=fad184d5 parentUuid=61f8085a ← summary text
L2091-2100 slash-cmd artifacts + 6 attachments (parents chain to each other)
L2103 13:50:40 user "про что был ..." uuid=f85e3125 parentUuid=cae6b94c ← PHANTOM
L2104 13:50:40 attachment(skill_listing) uuid=255eca43 parentUuid=f85e3125
L2105 13:50:47 assistant uuid=2c00c151 parentUuid=255eca43
L2106 13:50:57 assistant (text) uuid=c3ee7636 parentUuid=2c00c151 ← visible to user via TUI
cae6b94c does NOT exist anywhere in this JSONL or in any sibling/subagent JSONL across ~/.claude/projects/.
Same pattern observed on 4 other user prompts in the same session (L777, L1473, L1534, L1695) — all the first user prompt after some form of process restart / pause.
Environment
- claude-code: 2.1.146 (current latest)
- Platform: macOS Darwin 25.2.0
- Model: Opus 4.7 (1M context)
- Settings:
fileCheckpointingEnabled: false,autoCompactEnabled: false,alwaysThinkingEnabled: true,effortLevel: medium - Mode: terminal session embedded in a third-party terminal app (PTY)
Evidence this is not a recently introduced regression
Comments in #24304 confirm the same phantom-parentUuid pattern across v2.1.23, v2.1.38, v2.1.39, v2.1.71, v2.1.74, v2.1.86, and now v2.1.146 — every 2.1.x release.
The community has had to write external repair tools to compensate:
Both restore reachability by re-pointing phantom parentUuid to the physical predecessor line in the JSONL — but this is a workaround, not a root-cause fix. The root cause is somewhere in the resume-time write path: Claude needs to either (a) flush the in-RAM parent UUID to disk before the first user prompt after resume references it, or (b) re-establish parentUuid from the last on-disk entry instead of from RAM state.
Why this matters
/resume is a flagship feature. The bug silently corrupts long-running sessions — users lose hundreds-of-turns of context with no warning. Multiple comments on #21617 / #24304 express frustration ("how can such a key feature be broken for so long").
Two community workarounds exist (cc_jsonl_fix, custom UIs like ClaudeUI/Mantra). The root cause appears to be that Claude Code holds parent-UUIDs in process RAM that never get explicitly flushed before the next user message is written.
What would help
Two minimal interventions on Anthropic's side, in priority order:
- At resume time, deterministically pin
parentUuidof the first user message to the last on-disk entry's UUID. Never reference an in-RAM UUID that isn't on disk.
- Emit a warning to the user when reading a JSONL that has any phantom parentUuid references — at least tell the user the session is corrupt instead of silently truncating.
Both are byte-level changes, no behavior changes for healthy sessions.
---
Cross-referencing prior reports:
- #21617 — symptom (earlier messages lost on resume)
- #22526 — phantom UUID references
- #21751 — text blocks written to wrong file (prompt_suggestion subagent split)
- #24304 — file-history-snapshot collisions + phantom parentUuid
- #36583 — file-history-snapshot messageId / message uuid collision
- #40352 — compaction race condition during rate-limit
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗