[BUG] Claude Code Desktop — turn ends but UI stays "running": timer keeps counting, input blocked, while session list shows the session idle
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 turn finishes, the conversation view keeps showing the running indicator — the spinner plus an elapsed-time counter that keeps incrementing (e.g. 11m 43s · 5.2k tokens) — long after the assistant has stopped producing output.
Three UI surfaces disagree at the same moment:
| Surface | State shown |
|---|---|
| Conversation view (main pane) | Running — spinner + elapsed timer still counting |
| Session list (sidebar) | Idle/complete — the session's status dot is blank |
| Composer (input box) | Blocked — a new message cannot be sent; it waits for the spinner to end |
So the backend appears to consider the turn finished (sidebar is correct) while the front end both keeps the timer alive and blocks input.
Duration and behavior
- Stall length varies wildly: tens of seconds up to 22+ minutes observed.
- It eventually clears by itself. The wait seems roughly proportional to how long it was stuck.
- No tool call, no text, no visible activity of any kind during the stall. The spinner and the counting timer are the only things on screen.
- Happens frequently. It appears more often when other Claude Code sessions are open at the same time.
- The only workaround is quitting and restarting the app entirely — which for a long session is costly.
Why this is severe: once it stalls, that session is unusable until it clears or the app is restarted. Because it can happen to any session, having several open means one of them is intermittently frozen.
What Should Happen?
The desktop log records turn lifecycle events. Over 48 complete turns:
turns: 48 median 64.6s max 3753.7s min 2.7s
The longest gaps between consecutive log events are almost all bounded by control-channel messages (control_request / control_response), not by model or tool activity. Examples:
1350.0s control_request/mcp_status -> control_response
459.0s control_response -> control_response
345.9s control_response -> control_request/interrupt
300.5s control_response -> control_response
212.8s control_response -> control_response
201.7s control_response -> control_response
A representative stalled turn (UTC):
13:41:46.196 cli_turn_started
13:41:47 cli_ask_should_query_resolved
13:41:47 control_request/mcp_status
13:41:47+40s control_response <- 40.4s gap
... <- 548s of no lifecycle events
Observation about where cli_ask_turn_complete is emitted. In the 2.1.284 binary the emission site is:
let Fe = await this.turnRunner.run({ batch, input, tools, intake }); // turn work
let Fr = this.drainSettle.settleBatch({ batch, deliveredPollBatchUuids, turnEnd: Fe, turnSignal });
if (Fr) await Fr; // settle before signalling
V("info", "cli_ask_turn_complete", { should_query, batch_size, mode }); // completion signal
i.e. the completion signal is emitted only after drainSettle.settleBatch(...) resolves. If that settle does not resolve, cli_ask_turn_complete is never emitted — which would match what is seen: the conversation view never learns the turn is over, while the sidebar (a separate state source) correctly shows idle.
Possible lead, unverified: the call site passes { batch, turnEnd, turnSignal } while settleBatch is defined to destructure { batchUuids, deliveredPollBatchUuids, terminalReason, aborted }. Three parameter names do not line up. This may be a coincidence between two same-named methods on different classes (the code is minified so I cannot confirm), but it is worth a look.
Error Messages/Logs
Steps to Reproduce
Not reliably reproducible on demand — it is intermittent. Best reproduction attempts:
- Have more than one Claude Code session open.
- Run a long session (the transcript in this environment had grown past 80 MB).
- Let a turn complete and observe the conversation view after the assistant stops talking.
- Observe the three surfaces disagree: sidebar dot blank (idle), main pane spinner counting, composer refusing input.
Claude Model
Other
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
claude --2.1.284
Platform
Other
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
- The stall looks confined to the desktop front end / control channel — every piece of evidence above is local (control-channel gaps and UI state); no upstream request or response stream is implicated.
mcp_statusrequests appear at the start of every turn; the firstcontrol_responseafter them is frequently delayed by 16–40s. MCP connection times are much smaller in comparison (duration_msmedian 1551 ms, p99 12306 ms, max 21727 ms), so MCP does not account for the multi-minute stalls.- 3 of 115
mcp_connect_startingevents had no matching completion event.