[BUG] 2.1.27 session resume logic is loosing context
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?
Claude Code's session resume logic is not traversing the full parent chain when constructing the API request. It appears to only load recent messages rather than the complete history.
Impact
- High - Users lose all context when resuming sessions
- Makes --resume effectively useless for continued work
- Forces users to re-explain context or start new sessions
What Should Happen?
When resuming a session with --resume, Claude Code should load the complete conversation history from the session file and send it to the API. The full parent chain exists in the
JSONL file - it just needs to be traversed and included in the request.
After resume, Claude should have full context of all prior conversation and be able to reference earlier discussions, tool outputs, and decisions made during the session.
Error Messages/Logs
None - there is simply a lack of context.
Steps to Reproduce
In any session with some reasonable context, use the /context command to verify the quntity. Exit, launch claude again and /resume the previous session. /context reveals significantly less context - in some cases almost none
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.25
Claude Code Version
2.1.27
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Terminal.app (Ubuntu 24.04)
Additional Information
_No response_
19 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
# Claude CLI: Parent Chain Persistence Race Condition Causes Context Loss on Resume
Summary
Progress messages reference parent UUIDs before those parents are flushed to disk, creating broken parent chains that cause massive context loss when resuming sessions.
Impact
On
--resume, Claude CLI traces the parent chain from the most recent message to build conversation history. When this chain hits a broken link (missing parent), only the orphaned fragment is loaded instead of the full session.Observed: Resume loaded 4.5k tokens instead of 107k tokens (~4% of context).
Root Cause
Progress messages (hook events, tool progress, etc.) are written to the session JSONL with
parentUuidreferences to messages that have not been persisted yet. This creates orphaned chain segments.Example from affected session
L659 | 05:28:06 | assistant | uuid=346df931 | parent=8b6cf38a ← Old chain ends
| | (message e4124bda created in memory but never flushed)
L660 | 05:28:11 | progress | uuid=0bc43f20 | parent=e4124bda ← References missing parent
L661 | 05:28:12 | system | uuid=c5b09d7e | parent=0bc43f20 ← New orphan chain starts
Evidence
progresstype messagesReproduction
cache_creation_input_tokensin API response)Suggested Fix
Ensure parent messages are flushed to disk before child messages reference them, or write progress messages with the last persisted parent UUID rather than the last created parent UUID.
Workaround
Repair script that repoints broken
parentUuidreferences to the most recent valid ancestor by timestamp.See attached repair-sessions.py
Environment
Root Cause (Expanded)
CLI persistence race condition: progress messages are written with
parentUuidreferences to messages that have not been flushed to disk yet.(Note: The following is entirely prepared by Claude Code, and my role is nothing more than reproducing the symptoms and directing Claude Code as a non-technical guy. Please take everything with an extra grain of salt.)
___
Session Chain Breakage in
insertMessageChain/appendEntryWe've been hitting an issue where
/resumeloses most or all conversation history. After digging into the minifiedcli.js, we found what appear to be two independent mechanisms that each produce orphanparentUuidreferences, breaking the message chain. Both seem to remain unfixed as of v2.1.29.All references to minified
cli.jsin@anthropic-ai/claude-codev2.1.29 (11,139,710 bytes). Offsets are against the stock binary unless noted otherwise. Variable names are from the minified source — the actual source names will differ.How the session JSONL works
Claude Code persists each session as a JSONL file where every entry (user messages, assistant responses, progress events, etc.) has a
uuidand aparentUuidpointing to the previous entry. This forms a singly-linked chain. On/resume, the session loader walks backward from the last entry viaparentUuidreferences to reconstruct the conversation history for the API request.When a
parentUuidpoints to a UUID that doesn't exist in the file (an "orphan"), the chain walker can't find the parent and stops — everything before that point is lost. A single orphan near the start of the session means/resumerecovers only the entries after the break, which can be as little as the last message.Bug A: CIA cross-contamination from sidechain entries
File:
cli.js,appendEntrymethod (offset 10288159)appendEntrymaintains a memoized UUID Set (we're calling itCIA, offset 10308899) for dedup and chain anchoring. Sidechain entries (e.g.,prompt_suggestionsubagent responses) are correctly written to separate subagent files under<session-id>/subagents/, but their UUIDs appear to be added to the shared CIA Set:jh(offset 10290727) appears to be the main persistence function. It scans messages againstCIAto find the chain anchor — the last UUID already on disk — then callsinsertMessageChainwith that anchor as the initial parent:When
His a subagent UUID, the first entry written to the main JSONL getsparentUuidpointing to a UUID that only exists in a separate subagent file. On/resume, the chain walker hitsundefinedat that boundary.Reproduction: Start a session with hooks active. Wait for a
prompt_suggestionsubagent to spawn (visible as a suggested prompt in the input box). Send any message. The nextprogressentry in the main JSONL should haveparentUuidpointing to the subagent's assistant response UUID. Verify with:In our testing, every
prompt_suggestionspawn produced exactly 1 orphan. The orphan UUID could be found in the corresponding subagent file under<session-id>/subagents/.What fixed it for us: Short-circuit
O.add()for sidechain entries at offset 10289644:JavaScript short-circuit: when
$istrue(sidechain),!$isfalse, andO.add()is never called. Main-chain entries are unaffected ($isfalse→!$istrue→O.add()executes).Status: Appears unfixed as of v2.1.29.
Bug B: Spread-last override in
insertMessageChainFile:
cli.js,insertMessageChain(offset 10287565)JavaScript object spread: later properties override earlier ones. If
_(the React state message object) has aparentUuidfield, it replaces the computed sequential parent. From what we can tell, React state tracks the conversation as a flat tree where all messages are children of a single transient root node (system message / summary). That root node's UUID is never persisted to the main JSONL.In practice,
_.parentUuidoften seems to match the computedXbecause React state and the persistence layer track the same chain — making this bug latent under normal conditions. It appears to become the dominant phantom source when Bug A shifts the computed parent to a subagent UUID (which_.parentUuidwould not match), or when any other mechanism causesXand_.parentUuidto diverge.What fixed it for us: Spread-first at offset 10287565:
Computed properties now appear after the spread, so they always win regardless of what
_carries.Status: Appears unfixed as of v2.1.29.
Summary of fixes
| Fix | Bug | Location |
|-----|-----|----------|
| CIA sidechain filter in
appendEntry| A | offset 10289644 || Spread-first in
insertMessageChain| B | offset 10287565 |Both target code that appears unchanged between v2.1.27 and v2.1.29 — seemingly unfixed as of v2.1.29.
Verification
Post-fix JSONL chain integrity can be verified using the orphan-detection script above. Expected results with the CIA sidechain filter and spread-first fixes applied:
progressentries, which are expected dead-end leaves)New chat creation,
/resume, and cross-session switching all function correctly for us with fixes applied.This happens on 2.1.29 as well. My conversations are broken on resume.
Unfortunately the workaround script attached to this script broke the conversations even more, claude -c doesn't start after applying it.
Additional reproduction report
I encountered the same issue on v2.1.29.
Environment
Symptoms
claude -r <session-id>/compactbefore thisVerification
Ran the orphan UUID check script on my session file:
The session was fragmented into 4 disconnected chains. On resume, only the last chain (120 entries, ~7% of total) was accessible, causing massive context loss.
This confirms the Bug A (CIA cross-contamination) and Bug B (spread-last override) described in this issue.
Verification and Repair Script Update
@tfvchow - Analysis Confirmed
I've independently verified both bugs you identified in v2.1.29:
Bug A (CIA cross-contamination): Confirmed at offset ~10289644. The
appendEntrymethod adds sidechain UUIDs to the shared Set (O.add(A.uuid)) even when writing to subagent files. Thejhfunction then uses this contaminated Set for chain anchoring.Bug B (spread-last override): Confirmed at offset ~10287565. The
insertMessageChainuses:let D={parentUuid:J?null:X, ..._, /* spread last */}Allowing React state to override computed
parentUuid.Both patterns exist exactly as described.
---
@nakamurau1 - Reproduction Validated
I ran a similar analysis on 699 sessions:
| Metric | Value |
|--------|-------|
| Sessions with orphan UUIDs | 8 (1.1%) |
| Total orphan parentUuids | 28 |
| Unreachable entries | 2,371 (1.6%) |
| Orphans traceable to subagent files | 75% |
Your chain fragmentation pattern (4 disconnected chains, only last loaded on resume) matches exactly what Bug A predicts.
---
@tamasarpad - Repair Script Clarification
The repair script attached to this issue works correctly. I've been running it automatically on every session resume with no issues:
If
claude -cfailed after running the script, the cause was likely:.jsonl.repair-bak) - restore with:mv session.jsonl.repair-bak session.jsonlThe script only performs targeted string replacement on
"parentUuid":"<orphan>"references, repointing them to the most recent valid ancestor by timestamp. It does not restructure entries or modify message content.---
Automated Repair Integration
For anyone wanting to run repairs automatically on session resume, I've integrated this into my launch wrapper. The script:
Happy to share the integration approach if useful.
Please work on fixing this. Hours of prompting getting lost is not enjoyable.
I've finally twigged this is the issue I've been having too. It's super annoying.
You resume a conversation and in only remembers the last couple of posts. Nothing else. Not what plan it was working on. If you were working on a plan, entering and existing helps a bit to at least reboot the plan into memory, it seems. But Claude still remains absolutely oblivious to anything more than a comment back.
I've wasted so long thinking I'd been resuming the wrong chat, etc.
This is a serious bug, and definitely needs prioritising immediately. I'm amazed if nobody at Anthorpic is hitting the issue themselves.
Also, Claude is very annoying if you ask "don't you remember what you were working on?" and rather than saying "no", it just hallucinates what it might have been working on and starts "continuing" what it was doing.
If you don't mind, could you please tell me why you're downvoting my comment? Although all the technical details and writing are done by Claude Code, I did put a lot of effort in replicating the symptoms, experimenting with the fixes suggested by it, and ensuring the write-up is at least readable.
It is far from perfect, but that's what I can give as an amateur, and I don't see any further loss of context in resuming after applying the fixes.
---
IIRC, chats aren't gone for good. It is their UUIDs got messed up in the JSONL files. You can certainly ask Claude Code to write a script to get them back in order so you can resume the chat proper again.
It wasn't my intention to offend and I can understand how down-votes sting.
But I'll give you some feedback:
The OP reports one bug: session resume loses context. You've posted two
speculative "bugs" derived from AI analysis of minified code.
This pollutes the issue. Maintainers now have to evaluate whether your
findings are real or AI hallucinations from pattern-matching obfuscated
variable names. Minified code analysis is fragile and these "bugs" may not exist.
The OP gave maintainers everything they need: clear repro steps and a known
regression point (2.1.25 -> 2.1.27). With source access, they can diff those
versions and find the actual bug in minutes.
More useful: confirm the repro, add data points, or help bisect the commit. 🙂
_Sorry for adding more noise to this topic._
You're right. That's not the ideal way to report, and the search space could have been much smaller if I had taken the diff between two versions. I will definitely include it and "unminify" the code that if I ever have to do it again.
However, I stand by posting here to share with anyone looking for a workaround while waiting. I will just say not being able to fully resume a chat is far worse than receiving a down-vote, and I just don't have to deal with it, thanks to the fixes I shared.
Anyways, lesson learned and appreciate your thoughts. Hope someone will fix it soon.
Just happened to me. 2.1.31. Json is there, I can see the conversation on resume window, but in this particular case, ALL conversation was lost.
My last command was /quit , no crash and graceful exit
This is a frustrating regression — session resume should preserve the full conversation tree, not just a summary.
The deeper issue is that resume is doing too much "optimization" — it compacts or drops context during resume to save tokens, but in doing so loses the nuance and decisions from earlier in the session. You end up with a session that technically continues but has amnesia about what you discussed.
For a more reliable workflow, I have been using Mantra alongside Claude Code — it captures the full session state independently, so even if
/resumeloses context, you can browse the complete history in Mantra and manually re-inject the critical parts into your new session.Not ideal that we need a workaround for this, but it beats re-explaining 30 minutes of context from scratch.
thanks guys! my 20mb conversation bloody saved!
Overall just ask claude to find your missing conversation jsonl, give this issue url and ask to check for broken parentIds. Should wor
Postmortem: Claude Code Session Context Loss
Impact:
/resumereturned empty context — 97.1% of session history unreachable (280 of 9,789 entries visible from tail).Root Cause: Broken
parentUuidchains in session JSONL. Two entries referencedparentUuidvalues that didn't exist in the file. The session is a linked list walked from tail — a single broken link cuts off everything before it. Similar issue described in #22107, exact cause of orphan UUIDs unknown.Detection:
/resumecouldn't find resume-builder context. JSONL analysis revealed 2 orphanparentUuids — chain from tail only reached 280 entries.Fix:
fix-session.py— repoints orphanparentUuids to nearest previous entry with a valid UUID. Backup before modification, atomic write (tmp + rename), ran while Claude Code wasn't writing to the file.Result: Full chain restored,
/resumeworks.The session JSONL is getting fragmented into disconnected chains by orphan
parentUuidreferences — on resume, the walker hits the first broken link and only loads the tail fragment. There's a Python diagnostic script to count orphans and a repair script to repoint them. Root cause analysis + scripts: https://cacheoverflow.dev/blog/u-0oY5DW@rpl-james-overington2 I'm researching failures where session resume silently drops most of the working context instead of carrying the full task state forward. Your report is one of the clearest public examples because
--resumecan load only a small tail fragment of a much larger session, leaving the agent with partial history and no reliable sense of the earlier plan.If you're open to it, I'd value one short written postmortem here: https://www.agentsneedcontext.com/agent-failure-postmortem
I'm looking for five specifics: what the agent was trying to do before resume, what context was missing after resume, where that missing context should have lived, what workaround you used, and what it cost. No pitch, just research.
Still reproducible on v2.1.76, Windows 11, agent mode.
Same root behavior: resumed agent has zero knowledge of prior session work. In my case the agent had a MEMORY.md file with dozens of established decisions (Chrome profile paths, tested login strategies, which bat files to run). On resume, none of it was loaded. The agent re-researched everything from scratch.
The specific symptom I can add: even mid-session, spawning a sub-agent to "update memory files" and then continuing doesn't work. The sub-agent updates the files but the parent agent doesn't re-read them, so the loop of context loss continues.
The practical consequence in my case: time-critical automation (7:00 AM permit drop on recreation.gov, one shot per day) failed because the agent couldn't remember what it had already built and tested. Two months of automation work produced zero live value in the one window that mattered.
The PostCompact hook in v2.1.76 doesn't address this —
--resumeappears to be a separate code path that doesn't inject MEMORY.md or agent-specific instructions at startup.Cross-referencing: https://github.com/anthropics/claude-code/issues/34661 (filed this issue specifically for the
--resume+ MEMORY.md case)Session resume losing context usually happens because the JSONL file has grown beyond what the chain walker can cleanly reconstruct. Progress entries create parasitic forks in the parentUuid chain, and orphaned tool_results confuse the loader.
Cozempic v1.4.1 fixes both:
progress-collapseremoves all progress tick messages, and the executor's_relink_parent_chain()automatically repairs broken parent links.fix_orphaned_tool_results()removes tool_result blocks whose matching tool_use was lost.Run before resuming:
cozempic treat <session> -rx standard --executeOr install the guard for auto-protection:
pip install cozempic && cozempic initThe
doctorcommand also diagnoses these issues:cozempic doctorHitting this with Claude Code v2.1.117 in
claude -p --resume <uuid>mode when invoked by OpenClaw's Telegram bridge.OpenClaw deterministically passes the same
--resume <uuid>per chat_id across turns, but Claude CLI silently rotates to a new session UUID after each-prun, so the next turn's--resumelands on a stale/empty session and prior conversation context is lost.Reproducible across consecutive Telegram messages within the same chat. +1 — would really appreciate a fix that makes
-p --resume <uuid>either:(a) write the new turn back into the same UUID, or
(b) reliably error rather than silently creating a new session.