Repository navigation
Description
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
- In a top-level
claudeAgent/claude-opus-5-5thread (full access), have the agent callt3_worktree_handoffwith acontinuationPrompt(startFromOrigin: true,runSetupScript: false). - Let the thread continue. The worktree is created, the thread is rebound, and later turns run in the worktree.
- 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,
RunExecutionServicecloses open run-owned subagent rows (L687), but deliberately leavesdynamic_toolandcommand_executionitems 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 staysrunningforever. pendingBackgroundTurnItems(L178-L195) lists any active background-type item from any run that is notrolled_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
juliusmarminge commentedon Oct 5, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks for the thorough write-up, @letrandat. Your projection snapshot matches current
main(cf3e714b0f), and0.0.46-nightly.20261004.2657isn't missing a fix.What I found
t3_worktree_handoffrebinds the thread and schedulesprovider-session.detach. Claude sessions are exclusive, so that detach releases the whole session.releaseEntryfails every event subscriber withProviderAdapterEventStreamErrorbefore it closes the adapter, and the run is stored as failed with "The provider event stream closed unexpectedly…".finalizeActiveTurndoes 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, sodynamic_toolandcommand_executionitems stayrunning.A later run doesn't adopt them either. Inheritance requires the same provider thread, and the released Claude session no longer exists. Meanwhile
pendingBackgroundTurnItemsstill lists any active command, dynamic tool, or subagent whose run isn'trolled_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 asinterrupted, which is why it clears the banner even though nothing is running.The two outcomes depend on timing. If the Claude process exits first,
finalizeActiveTurncan publish the cancellation while subscribers are still attached, and the item endscancelled(what #15136 recorded). If the detach releases the session first, the cancellation is dropped and the item staysrunning, 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_toolandcommand_executionrows 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 opendynamic_toolandcommand_executionrows when a run settles, the same way subagent rows are handled.releaseEntry/finalizeActiveTurnordering. 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.
LetterXbox commentedon Oct 8, 2026
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:
advisor,mcp__t3-code__t3_worktree_handoff.dynamic_toolitems still markedrunning.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.
neobarthold commentedon Oct 10, 2026
Still reproducible on
0.0.46-nightly.20261010.2935(macOS desktop, Claude Opus 5.5, auto mode).t3_worktree_handoffcalled at 07:27:03; provider log showsquery.closeat 07:27:07 with notool_resultfor the call.failed; the continuation run started in the worktree and completed normally.dynamic_toolitem formcp__t3-code__t3_worktree_handoffstayedrunningfor ~2h, so the composer showed Waiting on background task mcp__t3-code__t3_worktree_handoff after every settled turn.interrupted.Happens on most sessions that use the handoff.
letrandat commentedon Oct 13, 2026
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):failedt3_worktree_handoff(withcontinuationPrompt,startFromOrigin: false,runSetupScript: false) at 04:08:23; the run ended at 04:08:24cancelleduserMessageIdmessage:mcp:…:worktree-continuation:…).queueHeld: true, never started, and stayed held for 56 minutes until it was cancelled at 05:04:37completedThe
dynamic_toolitem formcp__t3-code__t3_worktree_handoffin run 8 is stillstatus: "running",completedAt: null, two hours later. After every settled turn the composer shows Waiting on background task mcp__t3-code__t3_worktree_handoff, which matchespendingBackgroundTurnItemspicking up an active item from a non-rolled_backrun. 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.
letrandat commentedon Oct 13, 2026
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.MasterMann commentedon Oct 16, 2026
Still reproducible on v0.1.0 (Linux x64 server, desktop AppImage backend, used remotely from the Windows desktop app;
claudeAgent/claude-opus-5-5). Aftert3_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 staleAskUserQuestion, are in #15517 (comment).Produced by Claude Code (Claude Opus 5.5) via
t3 triage.sykoro commentedon Oct 19, 2026
Additional reproduction on v0.1.0 (macOS, local server,
grok/grok-4.7, full access). The provider event stream closed whilet3_worktree_handoffwas in flight, the tool row stayedpending, 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_handoffran at 2026-10-18T17:59:46Z withstartFromOrigin: false, an explicit worktree path,runSetupScript: false, and acontinuationPrompt.The
dynamic_toolrow was stored aspending(toolNamet3-code.t3_worktree_handoff,completedAtnull). It never received a tool result. At that same timestamp the run failed with: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.updateduntil 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.failedcancelledcompletedpendingThread B
Same provider and runtime mode. Handoff at 2026-10-18T18:21:26Z, this time with
startFromOrigin: trueandrunSetupScript: true, plus acontinuationPrompt. The item stayedpendingwithcompletedAtnull. 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 torunning. 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.pendingBackgroundTurnItemson currentmain(f740a97947cc) still lists any activecommand_execution,dynamic_tool, orsubagentwhose run is notrolled_back.pendingis an active status. After the latest run settles,derivePendingBackgroundWorkshows the handoff again. The last commit that touchedpackages/shared/src/orchestrationV2PendingBackgroundWork.tsis11ce406d2(#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.updatedthat sets the row tointerruptedis what removes it from that list. I wrote that event locally to clear the composer. It is not a product fix.NicolasMRQSCartage commentedon Oct 20, 2026
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).t3_worktree_handoff(startFromOrigin: true, with acontinuationPrompt). The worktree was created, then the run endedfailedwith "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).psicilia5179 commentedon Oct 25, 2026
Another trigger for the same leftover
runningturn 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'sdynamic_tool/command_executionitem is never finalized. A fix that closes background-capable items when a run fails because its query is gone would likely cover both.teamplayer3 commentedon Oct 27, 2026
Also seen on
0.1.3-nightly.20261027.3754withclaudeAgent/claude-sonnet-5-5(full access).After a
t3_worktree_handoffcall (withcontinuationPromptand the project setup script enabled), the thread keeps showing "Waiting on background task mcp__t3-code__t3_worktree_handoff", even though:t3_worktree_statusreportsattached: true),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: nulltool item described above.zayenz commentedon Oct 29, 2026
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 listsmcp__t3-code__t3_worktree_handoff/ "Background task" for hours after the thread went idle.What happened:
git fetchcould not authenticate). In the next run the agent fetched over HTTPS itself and calledt3_worktree_handoff(baseRef: origin/main,startFromOrigin: false, with acontinuationPrompt).failed0.5 s after the call, at 07:21:24.t3_worktree_statusreportsattached: trueon the new worktree, and no related processes are running.From a read-only copy of
statev2.sqlite: thedynamic_toolitem formcp__t3-code__t3_worktree_handoffin run 2 is stillstatus: "running",completedAt: null, more than 6 hours later. Every otherdynamic_toolandcommand_executionitem in the thread iscompleted.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.
Jacksondr5 commentedon Oct 31, 2026
Two more triggers for this, both reachable without a worktree handoff, and a trace of where the item gets left behind. Reproduced on
mainat8970a32104(Linux, Claude Haiku 5.5) andd487078f11(macOS, Cursor), on isolated test servers.Triggers
/logoutmessage does the same.)supportsRuntimeModeSwitchInSession: false, so the server detaches the session ("Runtime mode changed."). Same result: runfailed, provider turninterrupted, thecommand_executionitem and itstool_callnode stillrunningwith nocompletedAt, 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 callsfailSubscribersbeforecloseScopeWithin, so the adapter's turn finalizer, which normally settles open tool calls (ClaudeAdapterV2endToolCalls, CursorfinalizeTurn, ACPterminalizeOpenRunOwnedItems), 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 owncommand_execution/dynamic_toolitems and theirtool_callnodes aren't tracked there (activeBackgroundTurnItemsholds 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
interruptedbut leaves thetool_callnoderunning, 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
ProviderAdapterEventStreamErrorfromfailSubscribers), settle the run's open command and tool items and their nodes asinterruptedin the samewriteFinalRunEventswrite, and never on normalization or persistence failures, which addresses #17306's objection. Roughly 40–80 lines inRunExecutionService.tsplus 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.
Jacksondr5 commentedon Oct 31, 2026
A correction and a pointer, after building the fix I offered above.
fix/close-tool-calls-on-lost-provider-stream(f042e4de1a), and isn't visible on the closed PR. I built the same approach independently before seeing it, and it fixed both triggers above in tests, so I'd suggest reopening fix(server): a session released mid-turn no longer leaves tool calls running #17306 rather than taking a new PR from me.knownProviderFailureMessage) that drops it. And the error tag alone can't identify a provider loss, since the session manager may forward the adapter's own failure. Keying on the run's subscription stream, as fix(server): a session released mid-turn no longer leaves tool calls running #17306 now does, is what works.Claude Opus 5.5, an AI agent, on Jackson's behalf.
igaliney commentedon Nov 7, 2026
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-initiatedt3_worktree_handoffcalls on 2026-11-07, in 6 threads.What happened
In every case the handoff worked. The session detached, the calling run ended
failedwith "The provider event stream closed unexpectedly…", and the continuation run started within 61 ms of the failure and completed. The handoff'sdynamic_toolitem stayedrunningwithcompletedAt: nullinside thefailedrun, 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):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.interrupteffect, and about 80 ms later the item becameinterrupted(12:35:19–12:35:42 UTC). The other 2 items are stillrunning.Unchanged on current
mainChecked at
e455200. This is source reading only. I did not runmainor #29036.writeFinalRunEventsonly cascades run-owned subagents. Opencommand_executionanddynamic_toolitems of the run get noturn-item.updated(RunExecutionService.ts#L695-L712).releaseEntrystill callsfailSubscribersbeforecloseScopeWithin(ProviderSessionManager.ts#L1050-L1055).pendingBackgroundTurnItemslists any active item whose run is notrolled_back, so afailedrun does not exclude it (orchestrationV2PendingBackgroundWork.ts#L210-L226).listActiveShellIndexsetsmay_be_livefor any thread with an opencommand_execution,dynamic_toolorsubagentitem, without a check of the run status. So the thread stays in the live index after all its runs end (ProjectionStore.ts#L7259-L7264).The commits to
RunExecutionService.tsandProviderSessionManager.tsafter 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.Run it with
sqlite3 'file:~/.t3/userdata/statev2.sqlite?mode=ro'(expand~first). On this machine every row it returned was at3_worktree_handoffitem. 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.
bjpicciano commentedon Nov 7, 2026
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_handoffwith acontinuationPrompt. 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'sdynamic_toolitem stayedrunning, 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.
erazemkos commentedon Nov 9, 2026
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-initiatedt3_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):
t3_worktree_handoffwithbranchandcontinuationPrompt. No other tool call follows in that turn.worktreePath,branch,startedFromOrigin: true,setupScript.status: "no-script"andcontinuation: {status: "scheduled", delivery: "started"}.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.
EnjoyBacon7 commentedon Nov 10, 2026
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:
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.