Skip to content

[Bug]: Stale "Waiting on background task T3 Worktree Handoff" banner persists after a Claude worktree handoff #15993

Description

@letrandat

Before submitting

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

Area

apps/server

Steps to reproduce

  1. In a top-level claudeAgent / claude-opus-5-5 thread (full access), have the agent call t3_worktree_handoff with a continuationPrompt (startFromOrigin: true, runSetupScript: false).
  2. Let the thread continue. The worktree is created, the thread is rebound, and later turns run in the worktree.
  3. Finish several more turns, then look at the composer once the thread is idle.

Expected behavior

Once the handoff's turn ends, its tool item is settled, and the composer shows no pending work after later turns complete.

Actual behavior

The composer keeps showing "Waiting on background task T3 Worktree Handoff" with a Stop button, after 7 later turns that all completed normally. The agent has nothing running. When asked what it was waiting for, it confirmed the handoff had finished long before.

From the thread's projection (read from a copy of the state DB):

Run Status Note
1 failed "The provider event stream closed unexpectedly…" about 1.4 s after the handoff tool_use
2 cancelled the handoff continuation
3–8 completed normal turns inside the worktree

The dynamic_tool turn item for mcp__t3-code__t3_worktree_handoff in run 1 is still status: "running" with completedAt: null. Nothing will ever complete it, because the Claude session that owned it was released by the workspace-change detach.

Two pieces combine:

  • When a run reaches its final status, RunExecutionService closes open run-owned subagent rows (L687), but deliberately leaves dynamic_tool and command_execution items open so a late completion can arrive (L93-L101). That holds while the provider process is alive. Here the session was released, so the item stays running forever.
  • pendingBackgroundTurnItems (L178-L195) lists any active background-type item from any run that is not rolled_back, so the orphan from failed run 1 shows up again every time a later run settles.

This is related to #15136, which has the same trigger: the planned detach on handoff is treated as an unexpected stream close for Claude. There, the handoff item ended cancelled and the continuation stayed held. Here, the continuation was cancelled, later turns ran fine, and the handoff item was never settled. That suggests the item cleanup on detach is racy, and #15203 may not cover it because it changes how the detach ends the turn, not what happens to in-flight tool items. The same leftover probably appears whenever a session is released while a tool item is in flight. A quick scan of the same DB found 3 other threads with command_execution items still running from older runs.

Pressing Stop is the only way out, and it targets work that no longer exists.

Impact

Minor bug or occasional failure

Version or commit

0.0.46-nightly.20261004.2657

Environment

macOS, desktop app, local server, claudeAgent / claude-opus-5-5, full access

Logs or stack traces

run 1  failed     error item: "The provider event stream closed unexpectedly. Retry the turn; if it keeps failing, check the provider and server logs."
item   dynamic_tool  toolName=mcp__t3-code__t3_worktree_handoff  title="T3 Worktree Handoff"  status=running  completedAt=null

Filed by Claude Opus 5.5, running in T3 Code through the Claude Code harness, on behalf of @letrandat.

Activity

  1. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for the thorough write-up, @letrandat. Your projection snapshot matches current main (cf3e714b0f), and 0.0.46-nightly.20261004.2657 isn't missing a fix.

    What I found

    t3_worktree_handoff rebinds the thread and schedules provider-session.detach. Claude sessions are exclusive, so that detach releases the whole session. releaseEntry fails every event subscriber with ProviderAdapterEventStreamError before it closes the adapter, and the run is stored as failed with "The provider event stream closed unexpectedly…".

    finalizeActiveTurn does cancel open tool calls, but it runs while the session scope is closing, after those subscribers are gone, so the cancellation never reaches the run. Run finalization only closes open subagent rows, so dynamic_tool and command_execution items stay running.

    A later run doesn't adopt them either. Inheritance requires the same provider thread, and the released Claude session no longer exists. Meanwhile pendingBackgroundTurnItems still lists any active command, dynamic tool, or subagent whose run isn't rolled_back. So once a later turn settles, the composer shows Waiting on background task … for the handoff item. Stop works from the same list and marks items on a dead provider session as interrupted, which is why it clears the banner even though nothing is running.

    The two outcomes depend on timing. If the Claude process exits first, finalizeActiveTurn can publish the cancellation while subscribers are still attached, and the item ends cancelled (what #15136 recorded). If the detach releases the session first, the cancellation is dropped and the item stays running, which is what you're seeing. The same leftover can happen whenever an exclusive session is released while a command or dynamic tool is still running.

    #15136 is the same detach recorded as an unexpected stream close. Open PR #15203 turns a planned workspace detach into an interruption so the continuation can start, but it leaves in-flight dynamic_tool and command_execution rows alone, so this banner could still appear with that change.

    Workaround: press Stop on the banner. That settles the leftover items on the dead session, though it doesn't revive the handoff.

    Likely fix area

    • RunExecutionService / run finalization. One option is to terminalize open dynamic_tool and command_execution rows when a run settles, the same way subagent rows are handled.
    • releaseEntry / finalizeActiveTurn ordering. Another option is to publish the tool cancellations before failing subscribers on an exclusive-session release.
    • packages/shared/src/orchestrationV2PendingBackgroundWork.ts (pendingBackgroundTurnItems). A third option is to skip items whose provider session is already gone.

    A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 5, 2026
  3. LetterXbox commented on Oct 8, 2026

    @LetterXbox

    Additional reproduction on macOS desktop connected to a remote Linux server (0.0.46-nightly.20261007.2774), using Claude Sonnet 5.5 in Full access mode.

    The same stale-task pattern occurs, but the suggested Stop workaround does not clear it:

    • The composer shows Waiting on 2 background tasks: advisor, mcp__t3-code__t3_worktree_handoff.
    • Thread activity records both as dynamic_tool items still marked running.
    • Run 3 failed with "The provider event stream closed unexpectedly." The handoff continuation (run 4) was cancelled; runs 5–8 subsequently completed. The thread has no active run, but those two tool items remain pending.
    • Clicking Stop briefly changes the button to Stopping..., then it returns to Stop with both tasks still listed. This was reproduced directly in the macOS UI.

    The worktree handoff did take effect and later turns ran there, so this appears to be stale tool state after the failed handoff. The additional issue is that Stop fails to settle the leftover items in this case.

  4. neobarthold commented on Oct 10, 2026

    @neobarthold

    Still reproducible on 0.0.46-nightly.20261010.2935 (macOS desktop, Claude Opus 5.5, auto mode).

    • t3_worktree_handoff called at 07:27:03; provider log shows query.close at 07:27:07 with no tool_result for the call.
    • The handoff run ended failed; the continuation run started in the worktree and completed normally.
    • The dynamic_tool item for mcp__t3-code__t3_worktree_handoff stayed running for ~2h, so the composer showed Waiting on background task mcp__t3-code__t3_worktree_handoff after every settled turn.
    • In this case Stop did clear it: a later interrupted run moved the item to interrupted.

    Happens on most sessions that use the handoff.

  5. letrandat commented on Oct 13, 2026

    @letrandat
    Author

    Still reproducible on 0.0.46-nightly.20261013.3042 (macOS desktop, local server, claudeAgent / claude-opus-5-5, full access). One thread showed both this bug and #15136.

    From the thread's projection (read-only query of statev2.sqlite):

    Run Status Note
    8 failed Called t3_worktree_handoff (with continuationPrompt, startFromOrigin: false, runSetupScript: false) at 04:08:23; the run ended at 04:08:24
    9 cancelled The worktree continuation (userMessageId message:mcp:…:worktree-continuation:…). queueHeld: true, never started, and stayed held for 56 minutes until it was cancelled at 05:04:37
    10, 13, 17, 18 completed Normal turns in the worktree, after the user typed "continue"

    The dynamic_tool item for mcp__t3-code__t3_worktree_handoff in run 8 is still status: "running", completedAt: null, two hours later. After every settled turn the composer shows Waiting on background task mcp__t3-code__t3_worktree_handoff, which matches pendingBackgroundTurnItems picking up an active item from a non-rolled_back run. I did not press Stop.

    The run 9 data matches #15136: the continuation stays held after the planned detach, so the agent does nothing until the user sends another message. #15203 and #16749 are both still open.


    Filed by Claude Opus 5.5, running in T3 Code through the Claude Code harness, on behalf of @letrandat.

  6. letrandat commented on Oct 13, 2026

    @letrandat
    Author

    Follow-up to my comment above: pressing Stop on the "Waiting on background task mcp__t3-code__t3_worktree_handoff" banner did not clear it either. I clicked it several times and nothing changed. This was a local macOS server on 0.0.46-nightly.20261013.3042, so the Stop workaround failing is not limited to the remote-server setup @LetterXbox reported.

  7. MasterMann commented on Oct 16, 2026

    @MasterMann

    Still reproducible on v0.1.0 (Linux x64 server, desktop AppImage backend, used remotely from the Windows desktop app; claudeAgent / claude-opus-5-5). After t3_worktree_handoff, the composer kept showing "Waiting on background task mcp__t3-code__t3_worktree_handoff", and pressing Stop did not clear it. Details, including the interaction with a stale AskUserQuestion, are in #15517 (comment).


    Produced by Claude Code (Claude Opus 5.5) via t3 triage.

  8. sykoro commented on Oct 19, 2026

    @sykoro

    Additional reproduction on v0.1.0 (macOS, local server, grok / grok-4.7, full access). The provider event stream closed while t3_worktree_handoff was in flight, the tool row stayed pending, and the composer showed the banner again after later turns had finished.

    The server process started at 2026-10-18T17:45:09Z and was still that process the next day. Two Grok threads in the same database hit this within half an hour.

    Thread A

    t3_worktree_handoff ran at 2026-10-18T17:59:46Z with startFromOrigin: false, an explicit worktree path, runSetupScript: false, and a continuationPrompt.

    The dynamic_tool row was stored as pending (toolName t3-code.t3_worktree_handoff, completedAt null). It never received a tool result. At that same timestamp the run failed with:

    The provider event stream closed unexpectedly. Retry the turn; if it keeps failing, check the provider and server logs.

    The continuation run was queued at that timestamp and later cancelled. Later runs in the worktree completed. The handoff item had no further turn-item.updated until 2026-10-19T19:34:59Z, about 25.5 hours later. The next day, with the thread idle, the composer still showed Waiting on background task t3-code.t3_worktree_handoff.

    Run Status Note
    1 failed Handoff in flight; stream closed at 17:59:46Z
    2 cancelled Continuation queued at the same timestamp
    3–10 completed Later turns in the worktree, while the handoff row stayed pending

    Thread B

    Same provider and runtime mode. Handoff at 2026-10-18T18:21:26Z, this time with startFromOrigin: true and runSetupScript: true, plus a continuationPrompt. The item stayed pending with completedAt null. Run 1 failed with the same stream-closed message, run 2 was cancelled, and later runs completed. That item also had no update until 2026-10-19T19:34:59Z.

    What this adds

    The provider was Grok. The item status stayed pending; it never moved to running. The session here is not an exclusive Claude session, so this is the same banner from the stream closing before the tool result is written.

    pendingBackgroundTurnItems on current main (f740a97947cc) still lists any active command_execution, dynamic_tool, or subagent whose run is not rolled_back. pending is an active status. After the latest run settles, derivePendingBackgroundWork shows the handoff again. The last commit that touched packages/shared/src/orchestrationV2PendingBackgroundWork.ts is 11ce406d2 (#19751), and that change does not drop this leftover.

    The event log has no settle of either handoff item during the day they stayed pending. That matches the later reports that Stop leaves the banner up on an already-failed idle thread (#15993 (comment), #15993 (comment), #15993 (comment) on v0.1.0).

    A later turn-item.updated that sets the row to interrupted is what removes it from that list. I wrote that event locally to clear the composer. It is not a product fix.

  9. NicolasMRQSCartage commented on Oct 20, 2026

    @NicolasMRQSCartage

    Still reproduces on 0.1.0 (T3 Code (Beta) desktop app with its local server, macOS 27 arm64, top-level thread, claudeAgent / claude-opus-5-5, full access, Claude Code 2.1.304).

    • The agent called t3_worktree_handoff (startFromOrigin: true, with a continuationPrompt). The worktree was created, then the run ended failed with "The provider event stream closed unexpectedly". The continuation stayed queued and never started on its own ([Bug]: Claude child task dies after t3_worktree_handoff; continuation turn never starts #15136).
    • After that, every later turn completed normally inside the worktree, but the composer kept "Waiting on background task mcp__t3-code__t3_worktree_handoff". Stop does nothing, and only restarting T3 Code clears it.
    • Side effect: since the thread never looks idle, it never signals that the agent is done. It never settles or comes back as finished, so I only notice by opening it.
  10. psicilia5179 commented on Oct 25, 2026

    @psicilia5179

    Another trigger for the same leftover running turn item: #25054. A Claude thread is switched to Full access while an approval is pending, and the user types a reply. The adapter replaces the query, the old run fails with "provider event stream closed unexpectedly", and the declined tool's dynamic_tool / command_execution item is never finalized. A fix that closes background-capable items when a run fails because its query is gone would likely cover both.

  11. teamplayer3 commented on Oct 27, 2026

    @teamplayer3

    Also seen on 0.1.3-nightly.20261027.3754 with claudeAgent / claude-sonnet-5-5 (full access).

    After a t3_worktree_handoff call (with continuationPrompt and the project setup script enabled), the thread keeps showing "Waiting on background task mcp__t3-code__t3_worktree_handoff", even though:

    • the handoff completed (t3_worktree_status reports attached: true),
    • the setup script had exited (~25 s after the handoff) and no related processes were left,
    • the queue was empty (t3_queue_list), and the only running thread was the current one in a normal turn.

    So nothing is actually pending; the handoff tool call just never settles, same as the running / completedAt: null tool item described above.

  12. zayenz commented on Oct 29, 2026

    @zayenz

    Still reproducible on the stable 0.1.2 (T3 Code (Beta) desktop app with its local server, macOS 27 arm64; top-level thread, claudeAgent / claude-opus-5-5, full access). It also shows up on mobile: the Background work sheet lists mcp__t3-code__t3_worktree_handoff / "Background task" for hours after the thread went idle.

    What happened:

    • The first run of a new thread failed during workspace preparation (git fetch could not authenticate). In the next run the agent fetched over HTTPS itself and called t3_worktree_handoff (baseRef: origin/main, startFromOrigin: false, with a continuationPrompt).
    • That run (2) ended failed 0.5 s after the call, at 07:21:24.
    • Unlike [Bug]: Claude child task dies after t3_worktree_handoff; continuation turn never starts #15136, the continuation started at once (run 3) and completed normally. About 15 later runs, including delegated subagents and workflows, all finished.
    • t3_worktree_status reports attached: true on the new worktree, and no related processes are running.

    From a read-only copy of statev2.sqlite: the dynamic_tool item for mcp__t3-code__t3_worktree_handoff in run 2 is still status: "running", completedAt: null, more than 6 hours later. Every other dynamic_tool and command_execution item in the thread is completed.

    So the leftover item appears even when the handoff otherwise works perfectly. It looks like the handoff's own tool item is never settled once the detach fails the run. As earlier comments noted, it also keeps the thread from looking finished.

  13. Jacksondr5 commented on Oct 31, 2026

    @Jacksondr5
    Contributor

    Two more triggers for this, both reachable without a worktree handoff, and a trace of where the item gets left behind. Reproduced on main at 8970a32104 (Linux, Claude Haiku 5.5) and d487078f11 (macOS, Cursor), on isolated test servers.

    Triggers

    • Signing a provider out from Settings → Providers while another thread runs a shell command. The dialog warns that it stops running threads, and it does, but that thread is left with "The provider event stream closed unexpectedly. Retry the turn…" and a "Running: / Stop" row that survives reloads, signing back in, later successful turns and auto-settle. (A /logout message does the same.)
    • Changing Permissions mid-command and steering, from the web composer: Claude reports supportsRuntimeModeSwitchInSession: false, so the server detaches the session ("Runtime mode changed."). Same result: run failed, provider turn interrupted, the command_execution item and its tool_call node still running with no completedAt, and the row stays after the shell loop has long exited.

    Where it's left behind
    All of these, along with archive (#15135), worktree/workspace changes (#14245, this issue) and provider selection changes (#22755), end in ProviderSessionManager.releaseEntry. It calls failSubscribers before closeScopeWithin, so the adapter's turn finalizer, which normally settles open tool calls (ClaudeAdapterV2 endToolCalls, Cursor finalizeTurn, ACP terminalizeOpenRunOwnedItems), never emits. RunExecutionService's ingestion-failure handler then interrupts the provider turn and writes the failed terminal run events, but only cascades subagents (cascadeTerminalizeRunOwnedSubagents); the run's own command_execution/dynamic_tool items and their tool_call nodes aren't tracked there (activeBackgroundTurnItems holds ids only). The release reason ("Provider sign-in changed.", "Runtime mode changed.") never reaches that handler, which is why the message is the generic stream failure.

    Two smaller gaps nearby: the row's Stop clears the row and marks the item interrupted but leaves the tool_call node running, and startup recovery (ProviderRuntimeRecoveryService) selects threads by active items, so a node-only leftover is never cleaned up. A server restart does clear the item-plus-node case.

    A narrower fix than #16749 / #17306
    One point covers every trigger above: in that ingestion-failure handler, when the failure is the confirmed provider loss from a session release (the ProviderAdapterEventStreamError from failSubscribers), settle the run's open command and tool items and their nodes as interrupted in the same writeFinalRunEvents write, and never on normalization or persistence failures, which addresses #17306's objection. Roughly 40–80 lines in RunExecutionService.ts plus focused tests. Passing the release reason through would also let the message say why the turn stopped.

    I'm happy to send that as a PR, or leave it for a maintainer, whichever you prefer.

    Claude Opus 5.5, an AI agent, on Jackson's behalf.

  14. Jacksondr5 commented on Oct 31, 2026

    @Jacksondr5
    Contributor

    A correction and a pointer, after building the fix I offered above.

    Claude Opus 5.5, an AI agent, on Jackson's behalf.

  15. igaliney commented on Nov 7, 2026

    @igaliney

    Still reproduces on stable v0.1.7 (the current latest release): T3 Code (Beta) desktop app with its local server, macOS 27.2 arm64, claudeAgent / claude-opus-5-5, Claude Code 2.1.311. It happened on 6 of 6 agent-initiated t3_worktree_handoff calls on 2026-11-07, in 6 threads.

    What happened

    In every case the handoff worked. The session detached, the calling run ended failed with "The provider event stream closed unexpectedly…", and the continuation run started within 61 ms of the failure and completed. The handoff's dynamic_tool item stayed running with completedAt: null inside the failed run, so the composer showed Waiting · mcp__t3-code__t3_worktree_handoff with a timer that keeps counting.

    One thread, from a read-only query of statev2.sqlite (UTC):

    15:09:19.672  run 1  dynamic_tool t3_worktree_handoff  status=running, startedAt=updatedAt, completedAt=null
    15:09:20.074  effect provider-session.detach  succeeded
    15:09:20.077  run 1  failed  ("Provider error": "The provider event stream closed unexpectedly…", class unknown)
    15:09:20.087  run 2  requested (continuation), completed 15:11:07
    15:14–15:31   runs 3–7  completed in the new worktree
    15:36         handoff item still running (27 min), no pending effects, no pending runtime requests
    

    So nothing is still running: all 184 effects in the outbox are succeeded, and the thread is bound to the new worktree. I did not see the held continuation from #22971 in these 6 cases.

    Stop clears it on 0.1.7

    Earlier comments report that Stop did nothing. On 0.1.7 it worked 4 of 4 times. Stop on the idle thread wrote a provider-turn.interrupt effect, and about 80 ms later the item became interrupted (12:35:19–12:35:42 UTC). The other 2 items are still running.

    Unchanged on current main

    Checked at e455200. This is source reading only. I did not run main or #29036.

    The commits to RunExecutionService.ts and ProviderSessionManager.ts after v0.1.7 (#31656, #31807, #23901) do not touch this path, judged by their titles and the lines above. Open PR #29036 targets this leftover.

    Read-only check

    This query lists the leftover items. It should return no rows. I validated it: with 'interrupted' added to the item status list it returns the 4 items that Stop cleared.

    SELECT i.thread_id, r.ordinal AS run, r.status AS run_status,
           json_extract(i.payload_json, '$.toolName') AS tool,
           i.status AS item_status, i.updated_at
    FROM orchestration_v2_projection_turn_items i
    JOIN orchestration_v2_projection_runs r ON r.run_id = i.run_id
    WHERE i.type IN ('command_execution', 'dynamic_tool', 'subagent')
      AND i.status IN ('pending', 'running', 'waiting')
      AND r.status NOT IN ('queued', 'preparing', 'starting', 'running', 'waiting');

    Run it with sqlite3 'file:~/.t3/userdata/statev2.sqlite?mode=ro' (expand ~ first). On this machine every row it returned was a t3_worktree_handoff item. No other tool was left open.


    Investigated and written by Claude Code (Claude Opus 5.5) on behalf of the account owner, who reviews it before posting. Thread ids, paths and task text omitted.

  16. bjpicciano commented on Nov 7, 2026

    @bjpicciano

    Still reproducible on 0.1.8-nightly.20261107.4327 (Windows 11, desktop app, local server, claudeAgent / claude-opus-5-5, auto mode).

    The agent called t3_worktree_handoff with a continuationPrompt. That run failed with "The provider event stream closed unexpectedly." The continuation then started on its own and ran normally in the worktree, and 4 later runs completed. The handoff's dynamic_tool item stayed running, so with no active run the thread showed "Waiting · mcp__t3-code__t3_worktree_handoff".

    Pressing Stop cleared it, and the thread was then marked finished.

  17. erazemkos commented on Nov 9, 2026

    @erazemkos

    Still reproduces on stable v0.1.7: desktop app with its local server, macOS 26.6 arm64, claudeAgent / claude-fable-5-1, Claude Code 2.1.319. It happens on every agent-initiated t3_worktree_handoff. It happened on 2 of 2 handoffs on 2026-11-09, in 2 threads.

    What happened

    Timeline from the Claude Code session transcript of one thread (UTC):

    1. 14:37:24: the agent calls t3_worktree_handoff with branch and continuationPrompt. No other tool call follows in that turn.
    2. 14:37:26: the tool result arrives in the transcript with worktreePath, branch, startedFromOrigin: true, setupScript.status: "no-script" and continuation: {status: "scheduled", delivery: "started"}.
    3. 14:37:27: the run fails with "The provider event stream closed unexpectedly."
    4. 14:37:30: the continuation starts in the worktree. It runs and completes normally.

    After step 4, the composer still shows "Waiting · mcp__t3-code__t3_worktree_handoff" with a running timer and a Stop button. The handoff's tool result exists in the provider transcript, but the UI never settles the tool item.

  18. EnjoyBacon7 commented on Nov 10, 2026

    @EnjoyBacon7

    Same thing here on 0.1.6 (desktop app, local server, macOS 27.3 arm64, claudeAgent / claude-opus-5-5, full access, Claude Code 2.1.317). Happens on other threads too, not just this one.

    From the provider log:

    +0.000s  tool_use mcp__t3-code__t3_worktree_handoff (startFromOrigin: true, continuationPrompt set)
    +0.025s  message_delta stop_reason=tool_use
    +0.753s  query.close
    +1.873s  query.open in the new worktree, continuation offered
    

    No tool_result for the handoff ever shows up between the tool_use and the close. The agent's side does get the result once the session resumes (worktree created, continuation: scheduled, delivery: started), and the continuation ran fine in the worktree, so the handoff itself worked. Only the tool item is left hanging: the composer still says "Waiting on mcp__t3-code__t3_worktree_handoff" with the timer counting up well after later turns finished.

    No custom hooks run in that window (my only SessionStart hook is matched to startup|clear, and the resume hooks that do run all exit 0 after the new query opens), so I don't think anything on my side is involved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions