[BUG] Session resume loses 80%+ of conversation — progress entries create parasitic forks in parentUuid chain
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
On --resume, the session loads with most assistant responses and tool call details missing — user messages appear but the conversation between them is fragmented or absent. The JSONL file contains the complete conversation, but the chain walker that reconstructs history from parentUuid links takes wrong branches at fork points created by progress entries (hook events like PreToolUse, PostToolUse).
This is not just a UI rendering bug — the model itself has no memory of the lost content. When asked about edits made earlier in the session, it cannot recall them. The context is genuinely missing from the API conversation, not just hidden in the UI.
Screenshot — VSCode session view after resume. User messages are present but assistant tool calls (Bash, Grep, Read, Edit) show as collapsed one-liners with no expandable details. Entire multi-step workflows between user messages are missing:
<img width="830" height="857" alt="Image" src="https://github.com/user-attachments/assets/9b14acee-af05-4763-966c-5ebbce8da59b" />
Root cause: progress entries are written with the same parentUuid as real conversation entries (assistant tool_use / user tool_result), creating forks in the message tree. The chain walker uses a last-child heuristic that follows the progress branch instead of the conversation branch, skipping the real messages.
This is not the orphan-UUID problem from #22526 — all parentUuids are valid. And it's not context-window overflow — the full session is ~520K tokens, well within the 1M limit. It's a tree-topology bug: valid links, wrong traversal.
Evidence from a real session:
- 1064 JSONL entries, 946 with UUIDs
- 502 conversation entries (user + assistant)
- 446 progress entries (298 PreToolUse, 128 PostToolUse, 17 unknown, 3 SessionStart)
- 25 fork points where progress entries share
parentUuidwith conversation entries - Chain walk (last-child): only 96 of 502 conversation messages reachable (19%)
Example fork:
Entry 6: type=assistant tool_use:Bash uuid=9c2b95ec...
├─ Entry 7: type=assistant tool_use:Bash (real next message)
├─ Entry 8: type=user tool_result (real next message)
└─ Entry 42: type=progress hookEvent=PreToolUse ← walker picks this (last child)
The walker follows Entry 42 → a chain of 446 progress entries → eventually rejoins the conversation tail. Everything between Entry 7 and the rejoin point is lost.
What Should Happen?
progress entries should either:
- Not participate in the
parentUuidtree (noparentUuid/uuidfields), or - Be excluded from the chain walker's traversal, or
- Use a separate linking mechanism (e.g.
toolUseIDonly, notparentUuid)
On resume, the full conversation should be loaded into the model's context, including all tool calls and their results.
Error Messages/Logs
No error messages — the session resumes silently with missing context. The only symptom is the model's inability to recall earlier work.
Steps to Reproduce
Observed on a VSCode extension session with PreToolUse/PostToolUse hooks. The exact trigger is not confirmed — it may be hooks, parallel tool calls, or a combination. But the JSONL analysis clearly shows progress entries creating forks that break the chain walker.
- Run a session (VSCode extension) with hooks enabled that makes many tool calls
- Close the session
- Resume it (
claude --resume <session-id>or via VSCode) - Ask "what was discussed earlier in this session?" — model has no context
- Ask about specific edits made — model cannot recall them (not just UI, context is genuinely lost)
<details>
<summary>Diagnostic script</summary>
import json, sys
from pathlib import Path
from collections import Counter
session = Path(sys.argv[1])
entries = [json.loads(l) for l in session.read_text().splitlines() if l.strip()]
uuid_to_entry = {e['uuid']: e for e in entries if 'uuid' in e}
# Walk chain (last-child heuristic)
root = next(e for e in entries if 'uuid' in e and not e.get('parentUuid'))
current = root['uuid']
chain_set = set()
visited = set()
while current and current not in visited:
visited.add(current)
chain_set.add(current)
kids = [e['uuid'] for e in entries if 'uuid' in e and e.get('parentUuid') == current]
current = kids[-1] if kids else None
# Count what's reachable
in_chain = sum(1 for e in entries if e.get('type') in ('user','assistant') and e.get('uuid') in chain_set)
total = sum(1 for e in entries if e.get('type') in ('user','assistant'))
print(f"Conversation messages reachable: {in_chain}/{total} ({100*in_chain//total}%)")
# Show fork points
parent_counts = Counter(e.get('parentUuid') for e in entries if 'uuid' in e and e.get('parentUuid'))
forks = sum(1 for c in parent_counts.values() if c > 1)
print(f"Fork points: {forks}")
progress = sum(1 for e in entries if e.get('type') == 'progress')
print(f"Progress entries: {progress}")
</details>
<details>
<summary>Repair script (non-destructive — creates a new session file)</summary>
import json, sys, uuid
from pathlib import Path
src = Path(sys.argv[1])
entries = [json.loads(l) for l in src.read_text().splitlines() if l.strip()]
new_session_id = str(uuid.uuid4())
# Drop progress entries, rebuild linear chain
result = [e for e in entries if e.get('type') != 'progress']
# Update session ID in queue-operation entries
for e in result:
if e.get('type') == 'queue-operation':
e['sessionId'] = new_session_id
# Rebuild parentUuid chain linearly for conversation entries
conv_entries = [e for e in result if e.get('type') in ('user', 'assistant')]
prev_uuid = None
for e in conv_entries:
e['parentUuid'] = prev_uuid
prev_uuid = e['uuid']
# Write new session
dst = src.parent / f'{new_session_id}.jsonl'
dst.write_text('\n'.join(json.dumps(e) for e in result))
print(f"Repaired session: {dst}")
print(f"Resume with: claude --resume {new_session_id}")
</details>
Claude Model
Opus
Is this a regression?
YES
Claude Code Version
2.1.76
Platform
No idea
Operating System
macOS
Terminal/Shell
VS Code integrated terminal
Additional Information
Related issues:
- #22526 — orphan parentUuid (phantom UUIDs) — different mechanism, same symptom
- #24304 — multiple chain-break causes (broken refs, snapshot collisions, compaction) — overlapping
- #15837 — "resume doesn't preserve context" — same symptom, no root cause identified
- #22107 — "session resume logic is losing context" — same symptom
This issue has 9 comments on GitHub. Read the full discussion on GitHub ↗