Context Window Reattaches to Wrong Conversation After Power Loss

Status Fixed / completed
Maintainer reply None cached
Activity 7 comments · opened Apr 5, 2026 · closed Apr 12, 2026

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?

After a power outage interrupted a Claude Code VS Code session, the session resumed but reattached to a completely different point in the conversation history. The context window shows a different usage percentage and the model operates from a stale timeline, unable to process new user messages despite acknowledging them momentarily.

Context didn't shrink — it shifted to a different timeline: Going from 82% to 62% used is not compaction. If context had compacted, the model would still be at the same point in the conversation with a compressed history behind it. Instead, the model resumed at a completely different point in the conversation — hundreds of builds behind the actual state — even though the JSONL transcript is contiguous and contains the full correct history. The context window didn't roll back within the current session; it reattached to what appears to be an entirely older conversation state, as if it loaded a checkpoint from a different point in time.

The model is not ignoring instructions: It genuinely cannot see or retain the user's corrections. The stale context (~620K tokens of old-era conversation) statistically overwhelms the small number of recent corrective messages. This is not a behavior problem — it's a context poisoning problem.

JSONL continuity is intact: The JSONL file continued logging correctly throughout. The local transcript shows the real conversation. The problem is entirely in the API-side context state.

Potential cause: The power cut may have caused the Claude Code extension to reconnect to Anthropic's API with a corrupted or mismatched conversation ID, loading context from a different point in the conversation history. Alternatively, the extension may have attempted to rebuild context from the JSONL but selected the wrong portion.

What Should Happen?

Session resumes with the same context state (82% used), continuing from where the conversation left off. The model should be aware of the most recent work, not revert to a state from hundreds of builds prior.

Error Messages/Logs

Steps to Reproduce

  1. Start a long-running Claude Code session with high context usage (~82% used, 18% remaining, ~200K+ lines in session JSONL, ~990MB file)
  2. Power outage kills the VS Code process mid-conversation
  3. Power is restored; VS Code and Claude Code extension restart
  4. Resume the conversation in the same session

Observed after resume:

  • Context usage shifted from 82% used (18% left) to 62% used (38% left) — this is NOT compaction. Nothing was compacted. The context reattached to a completely different point in the conversation timeline.
  • Model resumed from a point approximately 240 builds behind the actual conversation state
  • Model references work (e.g., a "button fix") that was resolved hundreds of builds ago
  • User tells model it lost context due to the power outage; model acknowledges momentarily, then immediately reverts to stale context on the next response
  • Model attempts to edit source files to "fix" issues that no longer exist based on stale context — user had to interrupt tool uses to prevent destructive changes
  • No amount of user messages can correct the model's state; the stale context (~620K tokens) dominates every response
  • Lines L201160–L201234 in the JSONL are entirely file-history-snapshot entries (~75 consecutive snapshots with no user/assistant messages) — appears to be the extension dumping state during power cut recovery

Example exchange:

  • Model: "We're trying to fix the HD cover showing the wrong game after pressing Circle at root"
  • User: "no we are not"
  • Model: "I'm wrong. What are we doing? Tell me."
  • User: "i said it just 5 messages back., hold on i think something is wrong, you got compacted/detached twice?"
  • Model: "I don't remember you saying that. When did you say it?"

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

Claude Code VS Code Extension (version unknown at time of incident)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

Impact:

  • User unable to use the session for any productive work
  • Model attempts destructive code edits based on stale context (editing files to fix bugs that no longer exist)
  • Tokens wasted on messages the model cannot retain
  • The session handoff document (the exact thing being created to prevent context loss) was itself lost to the context corruption

To be absolutely clear: this is NOT compaction. Nothing was compacted. The context window did not shrink or compress the conversation. It reattached to a completely different point in the conversation history — approximately 240 builds behind the actual state — as if it loaded a checkpoint from a different point in time. Going from 82% used to 62% used is not something that can happen through normal compaction. The JSONL transcript is contiguous with no gaps. The problem is entirely in the API-side context state.

Workaround:

  • Force /compact to crush the stale context and let recent messages dominate
  • Or start a new session entirely with a recovery document

Suggested Investigation:

  1. What happens to the API-side conversation state when the client disconnects abruptly?
  2. Is it possible for the extension to reconnect to a different conversation turn or checkpoint?
  3. Can the extension validate that the resumed context matches the most recent JSONL entries before continuing?
  4. Should the extension detect a context usage decrease (which is impossible under normal operation) and warn the user?

Evidence from JSONL Transcript:

Before power cut:

  • Working on the latest build in the active development branch
  • Working on: session handoff templates, OSK cursor fix, license file, doc updates
  • Context: 82% used, 18% remaining

After power cut:

  • Model references old work involving a "Circle button fix" and source file edits — from approximately 240 builds prior to actual state
  • Model could not retain any corrections from the user (see example exchange in Steps to Reproduce)

Flood of file-history-snapshots: Approximately 75 consecutive file-history-snapshot entries with no user/assistant messages between them appear at the point of power cut recovery — appears to be the VS Code extension dumping state during recovery.

---

Update: Root Cause Identified via JSONL Forensic Analysis

The Dormammu Bug

After extensive forensic analysis of the session JSONL, we identified the exact mechanism causing the context reattachment.

The Orphaned Leaf Node

Every single time the session broke and reconnected, it landed on the SAME message:

L181422 [assistant] uuid=b2b74b9c-578b-409e-87cc-15f36070f8d5
timestamp: 2026-03-28T03:25:33
content: "Waiting."
parent: dabcbb1a-c4a7-4f81-92c3-78ef9a5d6ac3

This message was followed by a file-history-snapshot flood (L181426+) from a PREVIOUS session interruption on March 28. The conversation continued on a new chain after that, but L181422 was never given a child in the legitimate chain. It became a permanent orphaned leaf node.

Five Reattachments to the Same Node

Five separate messages across multiple session breaks ALL pointed to b2b74b9c as their parent:

| Line | Timestamp | Event |
|------|-----------|-------|
| L201237 | 2026-04-05 02:15 | First power cut recovery |
| L201597 | 2026-04-05 02:22 | Second reconnect attempt |
| L202286 | 2026-04-05 03:12 | Third reconnect attempt |
| L202894 | 2026-04-05 03:12 | Fourth (duplicate UUID — same message written twice) |
| L203970 | 2026-04-05 08:15 | Fifth reconnect after second crash |

The reattachment is deterministic, not random. The same orphan gets picked every time because the tip-finding algorithm consistently selects it.

Why THIS Specific Message

Analysis of all 1,272 leaf nodes in the session revealed the mechanism:

  1. L181422 ("Waiting.") was the last assistant message before a file-history-snapshot flood on March 28
  2. The conversation continued on a NEW chain after the March 28 flood — L181422 was never linked as a parent by any legitimate subsequent message
  3. L181422 became a permanent orphaned leaf — a dead branch tip with isSidechain: false
  4. When the April 5 power cut triggered another snapshot flood, the real conversation chain broke
  5. The tip-finder searched for the "latest" non-sidechain leaf node
  6. L181422 was consistently selected as the reattach point because it was the most prominent orphaned leaf in the chain graph

The Chain Break Mechanism

Before power cut (correct chain):

L203400 [user] → L203401 [assistant] → L203404 [user] → L203406 [assistant] → ...
     All parentUuids correctly chained

After power cut:

L203405-L203969: ~550 file-history-snapshot entries (no UUID, no parentUuid, no timestamp)

L203970 [user] parentUuid = b2b74b9c-578b-409e-87cc-15f36070f8d5
                             ↑ This is L181422 from March 28!!
                             ↑ 22,000 lines and 8 days backward

The break point:

L203404 uuid=b9d66c8d  parent=6185d669  ← CORRECT (chains to L203401)
   ... 550 snapshots ...
L203970 uuid=0940cb9b  parent=b2b74b9c  ← BROKEN (chains to L181422, March 28)

Impact on Token Usage

The broken reattachment caused Claude Code to rebuild context from the March 28 branch:

{
  "cache_creation_input_tokens": 593461,
  "cache_read_input_tokens": 11276
}

593K tokens of WRONG context were created and billed. The user's recent corrective messages (11K tokens) were statistically overwhelmed by 593K tokens of stale context. The model could not process corrections — it acknowledged them momentarily then reverted to the stale state on every response.

The Fix We Verified

We deleted L181422 (the orphaned "Waiting." message) from the JSONL. On next session open:

  • The tip-finder could no longer land on the March 28 orphan
  • It selected a different leaf node from the build #856 era (closer to present, but still not #1039)
  • After /compact, the model stabilized at build #856

This confirms the root cause: the tip-finder selects orphaned leaf nodes as reattach points. The fix is to filter the tip-finder to only consider user and assistant messages:

// Current (buggy):
let tip = findTip(messages.values(), (msg) => !msg.isSidechain);

// Fixed:
let tip = findTip(messages.values(), (msg) => 
  !msg.isSidechain && (msg.type === "user" || msg.type === "assistant")
);

Additional Finding: file-history-snapshot Entries

The file-history-snapshot entries that trigger the chain break have these properties:

  • type: "file-history-snapshot"
  • NO uuid field
  • NO parentUuid field
  • NO timestamp field
  • isSidechain not set (defaults to false)

They are written in bulk during session open/close/crash (~50-100 at a time). Because they have no parentUuid, they don't participate in chain-walking. But their presence in the JSONL appears to interfere with the chain reconstruction logic, causing the next real message to be assigned a parentUuid pointing to an old orphaned branch instead of the correct predecessor.

Related Issues

  • #33651 — Same root cause (progress messages), silent message loss
  • #37437 — Same root cause (403 retry), one-line fix identified
  • #40319 — Regression in v2.1.85 (progress entry elision), fix scripts available

All three issues describe the same fundamental bug: non-conversation entries (progress, file-history-snapshot) with isSidechain: false corrupt the parentUuid chain on session resume.

Forensic Tools Used

Analysis performed using custom JSONL forensics toolkit (clauder project):

  • session_search_mcp.py — CLI search across session transcripts
  • rebuild.py — Replay edit operations to reconstruct file states
  • Direct JSONL parsing to trace UUID chains and identify orphaned nodes

View original on GitHub ↗

7 Comments

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/33651
  2. https://github.com/anthropics/claude-code/issues/37437
  3. https://github.com/anthropics/claude-code/issues/40319

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

Leerz · 4 months ago

this needs to be fixed immediately. this is breaking workflows

Leerz · 4 months ago

Update: Token cost analysis of the parentUuid chain break

The bug burned through 98% of my hourly session token limit in approximately one hour — with ZERO productive work accomplished. 25% of my weekly allocation was consumed in a single day, entirely on recovery attempts.

Breakdown of token waste:

  1. Stale context cache creation: Each reconnect attempt triggered cache_creation_input_tokens: 593,461 — building a 593K token cache from the WRONG conversation branch (March 28 context loaded into an April 5 session). This happened on every session open.
  1. Unprocessable corrections: Every message I sent telling the model "you're in the wrong timeline, stop" was overwhelmed by ~600K tokens of stale context. The model acknowledged corrections momentarily, then reverted on the next response. Each correction + response = wasted tokens.
  1. Interrupted tool uses: The model repeatedly attempted destructive code edits based on the stale context (trying to git restore files to fix bugs from 240 builds ago). Each interrupted tool use still consumed tokens.
  1. Compaction on wrong state: /compact consumed tokens to compress the wrong timeline, locking the model into build #856 instead of the actual build #1039. Another full context rebuild on incorrect data.
  1. Multiple reconnect cycles: The bug is deterministic — the same orphaned leaf node was selected as the reattach point 5 separate times across multiple session restarts. Each restart triggered a full context rebuild from the wrong branch.

The numbers:

  • Hourly session limit: 0% → 98% in ~1 hour
  • Weekly limit: 25% consumed in one day (resets Friday, this was Saturday)
  • Productive output: Zero. No code written, no bugs fixed, no features added.
  • Root cause: A one-line bug in the tip-finder that doesn't filter by message type

This is a billing issue, not just a UX issue

Users are being charged for token usage generated by Claude Code's broken session resume logic. The context cache is rebuilt from incorrect conversation branches, and the user has no way to prevent it — the rebuild happens automatically on session open, before any user interaction.

The fix is one line:

// Filter tip-finder to only consider real conversation messages
let tip = findTip(messages.values(), (msg) => 
  !msg.isSidechain && (msg.type === "user" || msg.type === "assistant")
);

This has been identified by multiple reporters across issues #33651, #37437, and #40319. Please prioritize merging it.

vbonnet · 4 months ago

Additional findings: chain length as a compounding factor

While investigating this bug in long-running sessions (v2.1.101), I found an additional dimension to the problem that isn't covered in the original analysis.

Finding 1: The tip-finder fallback actually works (in v2.1.101)

By reverse-engineering the compiled binary, I found that Vt() has a fallback: when leafUuids (set B) has more than 1 entry, it walks backward from k (the last non-sidechain UUID by file order) to the nearest user/assistant message, clears B, and uses only that message. This means k — the last non-sidechain UUID in the file — effectively determines the tip in sessions with multiple leaf branches.

In the sessions I examined, this fallback was selecting the correct tip. The chain from the tip backward through parentUuid links was intact and pointed to the correct latest conversation turn.

Finding 2: Chain length causes context poisoning even with correct tip

Even with the correct tip, if the conversation chain is very long (6,500–9,200 messages in my cases), the context window fills from the root forward during compaction. The "recent" messages visible in context end up being from the middle of the chain — not the end. The model resumes operating from a stale point in the conversation despite the tip being correct.

Workaround: Truncate the JSONL to keep only the last ~1,500 entries of the main chain. Walk backward from k through parentUuid links to identify main chain entries, keep the tail, set parentUuid: null on the first kept entry. This brings the chain to a manageable length for context loading.

Finding 3: isSidechain byte-level parser silently ignores spaces

The fast JSONL parser (oT1) uses Buffer.from('"isSidechain":true') for byte-level matching — no space after the colon. If you write "isSidechain": true (with a space, as Python's json.dumps does by default), the fast parser treats the entry as isSidechain: false. This means programmatic JSONL repair scripts that use standard JSON serialization will silently fail to mark entries as sidechains for files above the oT1 size threshold.

Fix for scripts: Use json.dumps(msg, separators=(',', ':')) to produce compact JSON without spaces, or do byte-level replacement of "isSidechain":false"isSidechain":true (note: different lengths, so in-place replacement requires line rewrite).

Repair script approach

# Walk chain backward from k, keep last N entries
chain_uuids = set()
current_uuid = k  # last non-sidechain UUID
while current_uuid and current_uuid in uuid_map:
    chain_uuids.add(current_uuid)
    current_uuid = uuid_map[current_uuid].get('parentUuid')

# Keep last 1500 chain entries in file order
chain_entries = [e for e in entries if e.get('uuid') in chain_uuids]
kept = chain_entries[-1500:]

# Null the first entry's parentUuid to root the chain
kept[0]['parentUuid'] = None

# Write with compact JSON (no spaces) for oT1 compatibility
for entry in kept:
    f.write(json.dumps(entry, separators=(',', ':')) + '\n')

Related

This compounds with the original orphaned-leaf-node bug: a long-running session accumulates chain breaks from crashes/resumes, creating thousands of leaf branches. Even if the tip-finder selects the correct leaf, the sheer chain length means compaction can't show the recent conversation. The two bugs together make long-running sessions essentially unrecoverable without JSONL surgery.

🤖 Generated with Claude Code

Leerz · 4 months ago

as per 9772e13f820002c9730af67a2409702799c7ddc6
Fixed --resume/--continue` losing conversation context on large sessions when the loader anchored on a dead-end branch instead of the live conversation

  • Fixed --resume chain recovery bridging into an unrelated subagent conversation when a subagent message landed near a main-chain write gap`

they seem to indicate it as fixed

i've yet to restore my transcript backup and see if it finds the current context it should so i cannot confirm

Leerz · 4 months ago

as per https://github.com/anthropics/claude-code/commit/9772e13f820002c9730af67a2409702799c7ddc6

verified, i restored my previous transcript and it got back to the correct point in the conversation

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.