[Bug]: Cancelling a queued Claude continuation run leaves `requestedContinuations` set, so every later wake on that thread is dropped#30052

opened8d agobyBbaohappy02

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

  1. On a Claude thread, have the agent start a background task (a run_in_background Bash command or a background Agent) and end its turn.
  2. Make the task finish while the thread still has an active run, for example while a run from a user message is still running or finalizing. Claude starts a wake turn, T3 offers a continuation, and the continuation run lands in the thread's queue as queued.
  3. Cancel that queued continuation run before it starts. Use the queue UI or the MCP t3_queue tool with action: "cancel".
  4. Once the thread is idle, have the agent start another background task and end its turn.
  5. Let that task finish.

Expected behavior

A continuation run that ends without starting releases the wake latch for its native thread. This covers cancel and, by the same path, promote_to_steer. The wake in step 5 then opens a run, and its output shows in the thread.

Actual behavior

The wake in step 5 gets no run. The Claude CLI wakes and works anyway, but T3 does not own that turn:

  • None of its messages reach the thread, including the final report.
  • The thread shows Completed while the agent is still working.
  • Any T3 MCP tool called in that turn, such as t3_background_wait or t3_thread_send, fails with {"code":"parent_not_active","message":"The calling provider no longer owns an active thread run."}.

Every later wake on that native thread is dropped the same way until the query is reopened or the runtime restarts. User turns do not clear it.

From reading the bundled server code: bufferWakeMessage returns early when requestedContinuations already holds the native thread. That set is cleared in only two places:

  • in the continuation start path, right after attachTurn;
  • in clearWakeStateForNativeThread, which runs only on query reopen, a native-thread switch, or a runtime restart.

A queued continuation that is cancelled never reaches attachTurn, so its entry stays set. The same applies to one promoted with promote_to_steer, since its message moves into another run. I saw the cancel case live twice. The promote_to_steer case comes from reading the code only.

This is the same latch as #28163, which covers a failed wake dispatch. The trigger here is different and deterministic: it is a normal user or agent action, and the fix point is different too, since the cancel and promote paths would release the latch. It is related to #20430.

Impact

Major degradation or frequent failure

Version or commit

0.1.7-nightly.20261103.4106

Environment

macOS 26.5.1, desktop app, claudeAgent with claude-opus-5-5.

Logs or stack traces

shell
1Two incidents on 2026-11-03 (UTC), from `statev2.sqlite` and the provider event logs, on two different threads:
2
3| Thread | Continuation run (`userMessageId` `message:thread:…`) | Cancelled before start | Next wake |
4|---|---|---|---|
5| A | requested 08:00:59 while run 12 was active | 08:02:00 (`t3_queue` cancel) | 08:08:13: background subagent ends, Claude wakes at 08:08:17, no continuation offered (`server.trace` has none for this thread after 08:00:59, while other threads got offers at 08:08:19 and 08:08:37). `t3_background_wait` failed 3 times with `parent_not_active` at 08:08:36, 08:08:52 and 08:09:12. |
6| B | requested 08:47:34 while run 33 was finishing | 08:47:57 (`t3_queue` cancel) | 09:06:59: wake turn runs with no T3 run |

Screenshots, recordings, or supporting files

No response

Workaround

Avoid cancelling or promoting a queued continuation run; let it run. Reopening the provider query (or restarting the runtime) clears the latch.