[BUG] Desktop: older turns get re-delivered behind a `background_tasks_redelivered` marker and rendered last, so the feed ends on a turn from hours earlier

Status Open
Reported on v2.1.260
Maintainer reply None cached
Activity 0 comments · opened Sep 11, 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?

A Code session in the desktop app showed its conversation ending on a reply from 19:25, working marker below it, although sixteen turns had completed since, the last at 22:30, and I had been working in that very window until 22:13. It stayed that way for an hour and a half, through switches to other sessions and back, and a popout window of the session showed the same.

The transcript on disk was complete and in order. The page had all the data too, only in the wrong order. Read from the React tree of the stuck page:

  • The raw list of 4,438 stream messages ran in order up to 22:30:16 (a few rows shuffled within a turn aside), then held a synthetic row {"type":"system","subtype":"background_tasks_redelivered","tasks":[],"source_uuid":"…","session_id":"…"} without uuid or timestamp, then 477 rows from 18:32:26 to 19:24:37, the eight messages of that stretch and their replies. No uuid appeared twice, so the stretch was not duplicated but moved to the end
  • The 161 rendered entries had the same shape, entries 145-160, those eight exchanges, after the 22:30 turn. A feed anchored at the bottom therefore ends on the 19:24 reply, and since the list ends on a task notification rather than a result, the working marker shows below it
  • The transcript query (["epitaxy","transcript",<sessionId>]) returned the last 1,000 rows of the transcript in order, 19:24:37.438 to 22:30:16, plus that same marker as its last row. The re-delivered block ends at 19:24:37.435, three milliseconds before that page begins, and holds the user and assistant rows older than the page back to the first message after the compaction, plus the stream-only rows of those turns

The marker is not a CLI message, the CLI binary does not contain the string. The main process builds it from a background_tasks_changed event, and this one's source_uuid pointed at the background_tasks_changed of 17:01:26, the last before the compaction.

Timeline from main.log for the session (local_09ef21f1…), local time:

17:10:15  LocalSessions.sendMessage (that was /compact), 17:12:32 the compaction lands
17:42:32  [WarmLifecycle:preview] Idle timeout reached, disconnecting
18:30:28  [WarmLifecycle:preview] Warming up session      <- refocused after the disconnect
18:32-19:09  eight messages sent, seven turns - the block that later moved
19:24:37  a background task's task_notification, the block's last row (from the message list)
19:24:44  [WarmLifecycle:preview] Starting idle timeout   <- I had switched away, mid-turn
19:25:53  [Stop hook] Query completed
19:26:24  refocused, then fifteen turns of mine through 22:16
22:13:56  switched away again, mid-turn
22:25:09  another session's message, sent through the app's send_message tool, started one more turn
22:30:15  [Stop hook] Query completed, preview idle timer restarted
22:58:48  [WarmLifecycle:preview] Warming up session      <- refocused, feed already as described

No disconnect between 22:30 and 22:58, the idle timer had about ninety seconds left. When the re-delivery happened the logs don't say. The view was right at 22:13, when I last looked, and wrong at 22:58.

Reloading the page (Cmd+R) fixed it, everything came back in order, so the bad state lived in the page and the popout had inherited it. On that fresh load the console warned about 11 LocalSessions_$_onEvent listeners (below).

No conversation data crosses the network, the HAR across the reload holds only the page shell, app_start, /v1/code/sessions and telemetry. The transcript reaches the page over IPC.

What Should Happen?

A re-delivered batch merges into the list by uuid at its original position, or replaces the list wholesale. It never lands after newer messages.

Error Messages/Logs

Nothing errored. Log lines above. The only warnings on the fresh load after Cmd+R:

MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 $eipc_message$_…_claude.web_$_LocalSessions_$_onEvent listeners added. Use emitter.setMaxListeners() to increase limit
    at _addListener (sandbox_bundle:2:35008)
    at IpcRenderer.addListener (sandbox_bundle:2:37894)
    at Object.onOnEvent (mainView.js:1:114542)

Steps to Reproduce

Not reproducible on demand. The shape of it:

  1. Work in one long session (mine had about 7,600 transcript rows, 30 MB) and run /compact
  2. Leave it for more than 30 minutes so the preview disconnects (Idle timeout reached, disconnecting), come back and run a few turns
  3. Switch away mid-turn while a background task is completing, come back, run more turns
  4. Switch away mid-turn once more, let a turn run and finish unfocused, come back half an hour later

The feed then ends partway through the turn that was running at step 3's unfocus, working marker below it, with the turns from step 3 sitting above those from step 2.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

Unknown

Claude Code Version

2.1.260, bundled in Claude desktop 1.49585.0 (2.1.266 arrived the morning after)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Claude desktop app 1.49585.0, Code tab, macOS 26.5.1 (25F80).

Related, all open, none the same defect:

  • #92197, the desktop renders an older branch after a compaction and hides the newest days, and my #92089 saw the same shape after a second /compact. Data intact there too, but content missing rather than reordered, and it survives restarts where a reload fixed this
  • #88428 and #84858, a conversation reopened after a restart shows no transcript at all, with the data retained
  • #83247, returning to a session leaves the scroll where it was. Here the view was at the bottom, and the bottom was wrong
  • #92610, the same WarmLifecycle:preview subsystem tearing down a different surface

View original on GitHub ↗