Session resume loses conversation messages when SubAgent progress chain overtakes main conversation chain

Resolved 💬 9 comments Opened Mar 12, 2026 by hatawong Closed May 20, 2026

Summary

When resuming a session (via --resume, VS Code reload, or process restart), conversation messages can silently disappear from both the UI and LLM context. This happens when a SubAgent's progress messages create a parallel parentUuid branch that has a slightly newer timestamp than the main conversation branch.

Steps to Reproduce

  1. Start a conversation where the main agent dispatches a SubAgent via the Agent tool
  2. The SubAgent runs and generates progress messages (chaining parentUuid from the assistant message that made the Agent tool_use call)
  3. Meanwhile, the main agent receives the SubAgent result and continues the conversation for several turns
  4. The SubAgent's buffered progress messages are flushed to the JSONL after the main conversation messages, so the last progress message has a timestamp slightly newer than the last conversation message
  5. Kill the CLI process (pkill) or restart VS Code
  6. Resume the session

Expected Behavior

All conversation messages (user + assistant) should be visible in the UI and present in the LLM context after resume.

Actual Behavior

The conversation messages between the SubAgent dispatch and the next independently-rooted message are silently lost — gone from both the UI and the LLM context. Only the progress chain path is preserved.

In my case, 28 messages (including substantive assistant analysis and user responses) disappeared after resume with zero indication.

Root Cause

The parentUuid chain reconstruction during session resume picks the most recent non-sidechain message as the tree tip, then traces backwards. Progress messages are not treated as sidechain, so they participate in tip selection.

When the main agent calls a SubAgent, two branches grow from the same parent node:

L_agent (assistant, Agent tool_use)
├── Branch A: tool_result → conversation continues → ... → L_last_conv (ts=T1)
└── Branch B: progress → progress → ... → L_last_progress (ts=T2)
        └── system message → user message → ... (post-resume conversation)

If T2 > T1 (which happens when progress messages are buffered and flushed after conversation messages), the chain reconstruction follows Branch B, and Branch A is completely orphaned.

The post-resume system/user messages chain from the last progress message (Branch B), so once the session is resumed, all subsequent messages are on Branch B. The conversation in Branch A becomes permanently unreachable.

Suggested Fix

Exclude progress messages from tip selection during chain reconstruction. Progress messages don't enter the LLM context by design, so they shouldn't influence which conversation branch is selected.

Something like:

// Current: only excludes sidechain
.filter((P) => !P.isSidechain)

// Fix: also exclude progress
.filter((P) => !P.isSidechain && P.type !== "progress")

Impact

  • Silent data loss: No warning or indication that messages were dropped
  • Not rare: Triggers whenever SubAgent progress flush is delayed relative to main conversation — common with long-running SubAgent tasks
  • Not pkill-specific: Any session reload (VS Code restart, --resume from CLI, window reload) can trigger this if the JSONL tree has this branching structure

Environment

  • Claude Code VS Code extension
  • macOS

View original on GitHub ↗

This issue has 9 comments on GitHub. Read the full discussion on GitHub ↗