claude-code - 💡(How to fix) Fix JSONL transcript corruption: phantom parentUuid on first message after resume (v2.1.146, Opus 4.7)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

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-snapshot collision (I have fileCheckpointingEnabled: false)
  • Not subagent prompt_suggestion text-block split (verified: no matching UUIDs in agent-*.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.

Root Cause

/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.

Fix Action

Fix / Workaround

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.

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.

Code Example

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
RAW_BUFFERClick to expand / collapse

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-snapshot collision (I have fileCheckpointingEnabled: false)
  • Not subagent prompt_suggestion text-block split (verified: no matching UUIDs in agent-*.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

  1. Start a session, do work
  2. Run /compact (manual)
  3. Type a prompt → see Claude respond fully
  4. Exit (Ctrl+C×2 OR close terminal OR system shutdown — multiple variants tested)
  5. claude --resume <session-id>
  6. 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:

  1. At resume time, deterministically pin parentUuid of the first user message to the last on-disk entry's UUID. Never reference an in-RAM UUID that isn't on disk.

  2. 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

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix JSONL transcript corruption: phantom parentUuid on first message after resume (v2.1.146, Opus 4.7)