Repository navigation
Claude session idle-released while its run waits on a delegate_task child; Stop and Settle then fail permanently #15173
Description
What happened
A V2 Claude thread can't be stopped or settled. I press Stop and nothing happens; Settle is refused. Messages I send ("stop", "stop working") queue up and never start. The thread had used delegate_task to start a Codex reviewer, and that reviewer sat on an approval prompt.
Diagnosis
The Claude session is released after 30 minutes idle while its run is still waiting on an app-owned delegated child (delegate_task). After that release, nothing in the UI can end the run.
- The parent Claude run calls
delegate_task(Codex child), and its native turn ends (end_turn). T3 correctly keeps the runrunningwhile it waits for the app-owned child. The child is slow; here it waited on an approval prompt. ProviderSessionManager.releaseIfStillIdle(apps/server/src/orchestration-v2/ProviderSessionManager.ts~L864–940) only defers release forruntime.hasPendingBackgroundWork, the adapter's native background work. It doesn't count an app-owned delegated child of a running run. Exactly 30 minutes afterend_turnthe Claude session is released (query.close), and the session is persisted asstopped. The provider turn row staysrunning.- Stop (
run.interrupt) fails. InOrchestrator.tsthesettleOnlyfallback (~L7926) applies only whenproviderTurn.status !== "running"and the session is gone. A running turn with a released session falls through to the live-session path and fails withProvider session … is not active.(~L7978). thread.settlefails withhas active or blocked work and cannot be settledbecause the run is stillrunning.- When the delegated child ends, its completion notice is queued as a new run behind the wedged run. User messages are queued the same way. Neither ever starts, and promote-to-steer fails for the same reason.
Only a server restart clears it (startup reconciliation ends unfinished runs). Restarting interrupts every other active thread on the server.
The same parent-session release probably explains the parent_not_active errors other threads got from delegate_task while their parent was waiting on a child.
Both code paths are unchanged on main as of 2026-10-03 (releaseIfStillIdle is identical; settleOnly still requires a non-running turn).
Steps to reproduce
- On a V2 Claude thread, have the agent call
delegate_taskfor a Codex child that won't finish within 30 minutes. For example, useruntimeModeapproval-required with a prompt that triggers a command approval, and leave the approval unanswered. - Let the parent's Claude turn end while it waits for the child. Wait just over 30 minutes (default idle timeout). The provider event log shows an outgoing
query.close, and the provider session becomesstopped. The run, run attempt, root node and provider turn all stayrunning. - Press Stop on the parent thread. It fails with
Provider session … is not active. - Press Settle. It fails with
has active or blocked work and cannot be settled. - Send a message. It queues and never starts. Promoting it to steer fails.
Version
Desktop app 0.0.46-nightly.20261003.2610 (8ed276c); CLI 0.0.45
Environment
Linux x64 (kernel 7.0.0), desktop AppImage, Node v26.8.2; parent provider claudeAgent (claude-opus-5-5), delegated child codex
Evidence
# Provider event log (parent thread): turn ends, then idle release exactly 30 min later
[2026-10-03T10:31:30.363Z] incoming result stop_reason=end_turn
[2026-10-03T11:01:30.935Z] outgoing {"type":"query.close"}
# Projection state (statev2.sqlite) for the parent thread afterwards
run ordinal 1 status=running (since 10:21:41Z, completed_at NULL)
provider_turn 1 status=running
provider_session status=stopped updated_at=11:01:30.936Z
subagent (codex, app_owned, delegate_task) status=interrupted completed_at=12:11:56Z
run ordinal 3 (delegated-completion notice) status=queued
run ordinal 5 (user "stop working") status=queued
# Server trace: 13 run.interrupt attempts between 12:07 and 12:14, all failed
OrchestratorDispatchError: Failed to dispatch orchestration command run.interrupt (...)
[cause]: Error: Provider session provider-session:provider-instance:claudeAgent:thread:<id>:<uuid> is not active.
OrchestratorDispatchError: Failed to dispatch orchestration command thread.settle (...)
cause: Thread <id> has active or blocked work and cannot be settled.
OrchestratorDispatchError: Failed to dispatch orchestration command queued-message.promote-to-steer (...)
cause: Provider session ... is not active.Related issues
No existing issue. Closed, unmerged PRs addressed parts of this: #14857 (Stop ends a V2 run whose session is gone, which is exactly the Stop half; closed 2026-10-02 without merging), #14507 (settle a run when its idle session is released; closed), and #14856 (event-consumer failure as a different trigger for the same stranded-run state). #14507's report had a different trigger (pinned native background work that expired after 4 h). This report adds a trigger that needs no failure at all: an app-owned delegate_task child that is still working when the parent's 30-minute idle release fires. #15124 is a different stuck-waiting-run cause (stalled checkpoint capture).
Fix applied or workaround
None applied yet. Workaround: delete the queued messages on the stuck thread so it doesn't resume unexpectedly, then restart the app (startup reconciliation ends the run), then settle the thread.
Filed by
Claude Code (Claude Opus 5.5) via t3 triage
Activity
juliusmarminge commentedon Oct 3, 2026
Note
Grok responding on behalf of Julius.
Triage
Thanks @areidyOTH for the detailed diagnosis, the code pointers, and the timing evidence. I confirmed this on
main(31a9da179). It's a real stuck state, and it's separate from #15124 (that one is awaitingrun whose checkpoint capture never finishes).Why Stop, Settle, and steer fail
This matches your report.
dispatchRunInterruptonly takes the session-gone path when the provider turn is already notrunning(Orchestrator.ts,settleOnly). A turn that's stillrunningafter its session was released falls through and errors withProvider session … is not active.thread.settlethen refuses the thread because arunningrun counts as active work. Promote-to-steer hits the same dead session, so the queued user message and the delegated-completion wake never start. Only a server restart recovers it, because startup reconciliation is what ends the unfinished run.Why the session was released
Also as you described.
releaseIfStillIdledefers only whilehasPendingBackgroundWorkis true, and for Claude that covers native background tasks, native session subagents, and wake buffers. An app-owneddelegate_taskchild is none of those, so it doesn't pin the session, and the default 30-minute idle timer runs. The gap fromend_turnat 10:31:30Z toquery.closeat 11:01:30Z matches that timer. The session pump marks the session idle when it seesturn.terminal, which starts the timer.One correction to the causal chain
T3 doesn't intentionally keep the run and provider turn
runningafter that terminal. A rootturn.terminalthat the run consumer ingests is persisted aswaiting(RunExecutionService.writeFinalRunEvents), and the provider turn leavesrunning. Since your captured rows were stillrunning, that terminal likely never landed on the projection, even though the session manager saw it and later released the session. That's the same stranded-projection class as the open PR #14856 and the closed, unmerged PRs #14507 (settle the run when the idle session is released) and #14857 (Stop settles a running turn whose session is gone). The app-owned child explains why the release wasn't deferred, but on its own it doesn't explain a provider turn that staysrunningafter a persistedend_turn.The
parent_not_activeerrors aren't established by this capture.delegate_taskreturns that when the caller has no active run owned by its provider, and this parent run was stillrunning, which passes that check. Releasing the session revokes the MCP credential separately.Optional extra evidence
If you still have the trace, whatever the server logged around 10:31Z when the
end_turnresult arrived would help narrow it down. An event-write failure would make this the #14856 trigger, while a live consumer that dropped the terminal would be a separate routing bug.A maintainer will decide on the fix direction.
areidyOTH commentedon Oct 3, 2026
Thanks. Correction on
parent_not_activeaccepted.The server trace around 10:31Z has rotated out (only 3 spans survive for 10:21–10:23), but the persisted event log narrows it down. The run consumer stopped persisting at 10:22:21.623Z, nine minutes before
end_turn, not at the terminal:node.updated/turn-item.updated(completed at 10:22:21.6Z). Its provider event log shows 53tool_useblocks in total, assistant text, and theresultat 10:31:30Z. None of the 52 later tool calls, the text, or the terminal were persisted.delegate_tasksubagent/node/turn-item rows at 10:31:20.538Z (MCP command path), thenprovider-session.updated stoppedat 11:01:30.936Z.So it looks like the consumer stopped ingesting (or routing) mid-turn rather than the #14856 write-failure path, though a transient write failure at exactly 10:22:21 can't be excluded without the trace. One possibly relevant detail: a
thread-sendfrom another thread queued run 2 on the same provider thread at 10:21:50Z, while run 1 was stillpreparing(its provider turn started 10:22:09Z).Filed by Claude Code (Claude Opus 5.5) via
t3 triage.postoso commentedon Oct 5, 2026
Another occurrence on macOS,
0.0.46-nightly.20261004.2657. One difference from the original report: neither delegated child was still pending when the session was released. Both had already completed, and the run stayedrunninganyway.Timeline (UTC, from the provider event log and
statev2.sqlite):claude-opus-5-5)delegate_taskchildren (codex)dynamic_tool)tool_useand itstool_result, and the final assistant text. None of these are inorchestration_v2_projection_turn_items.result/success/terminal_reason: completedsubagentandnotificationturn items are persisted, so app-sourced writes for this run still worked.query.close, 30 minutes after the last child completion (not afterend_turn)State afterwards: run, run attempt, and provider turn are all
running; provider sessionstopped(updated 01:43:09.399Z); both subagent rowscompleted; no queued runs.run.interruptand a restart-mode send (message.dispatch, via thet3_thread_sendMCP tool) both fail the same way:On the triage question about an event-write failure vs. a dropped terminal: the provider-sourced events stopped persisting about 22s before the
result, while app-sourced items kept landing three minutes later. That matches the consumer-stopped-early pattern in the comment above, and points at the #14856 class rather than the terminal alone being dropped. I can't tell you what the server logged at 01:09:44, because the trace had already rotated out. The 10 trace files cover about 15 minutes under this load.GeorgeFL7 commentedon Oct 12, 2026
Two more occurrences today on Linux arm64,
0.0.46-nightly.20261003.2632(local server, Claude parentclaude-opus-5-5, Codex children viadelegate_task). Both threads failed the same way, on different projects, within 40 minutes of each other.They match @postoso's variant: the provider session was not idle-released, and the children had already finished. The run consumer had stopped persisting the parent's provider items about 45 minutes before
end_turn.Timeline (UTC, thread A: provider event log,
t3_thread_read, Claude session jsonl)ordinal:13startsreasoningitem)link_pull_request, and starts 2delegate_taskCodex reviews. All of it is in the provider event log and the Claude jsonl, but none of it is in the T3 timeline.ordinal:14andordinal:15,cancelledwithstartedAt: nullabout 1–8 s laterresult stop_reason=end_turn. The last message says it is waiting on the second review.ordinal:16andordinal:17, alsocancelled, never startedquery.closeat 08:42: the session was still alive 79 minutes afterend_turnt3_thread_interruptreturnsinterrupt_requested, and aquery.closeis logged at 09:31:52. The run staysrunning.t3_thread_sendmodeautoreturnsdelivery: "steered"intoordinal:13. The Claude jsonl records twoqueue-operationentries, but no turn starts.t3_thread_sendmoderestartfails:Thread 5E1345E5-… has active or blocked work and cannot be settled.A second interrupt is also a no-op.Thread B (another project) has the same shape: the parent starts 3 Codex reviews,
end_turnat 08:52:23 says it is waiting on them, the children complete, and the parent is never woken. Later user messages are dropped, and Stop does nothing.Observations
thread_readstill showsactiveRunId: ordinal:13,status: running,pendingRequestCount: 0, and an empty queue (t3_queue_listreturns[]).t3_thread_organize action=archivesucceeds and removes the thread from the list. Continuing the work requires a new thread on the same worktree. We didn't restart the server, to avoid interrupting other active threads.