You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Command approvals stay pending after a delegated task is cancelled #21935
What happens: on 0.0.46-nightly.20261008.2819, two delegated Codex tasks were each blocked on a pending shell-command
approval. Each was cancelled by its parent agent's task_cancel call, and both runs are now interrupted. Their command
approval requests remained pending afterwards. A comparable delegated Claude task's pending file-read approval, cancelled
the same way, was cleared.
This one sample shows inconsistent cleanup between the two delegated tasks. It does not establish a Codex-only bug. The
provider-specific cause is not traced; the records were found by read-only state inspection.
Expected: when a run is interrupted or cancelled, its unresolved approval requests are withdrawn, because their provider
callbacks no longer exist. They should then no longer count as pending.
Thanks for flagging the difference between the two providers. Current main explains it.
When a provider turn ends, including when it is interrupted, the server only withdraws pending user input requests. The query that finds them is limited to that kind (apps/server/src/orchestration-v2/ProjectionStore.ts:4429-4437; apps/server/src/orchestration-v2/ProviderEventIngestor.ts:579-585, :680-681). Pending approvals are only released when the whole provider session closes or fails (apps/server/src/orchestration-v2/ProviderSessionManager.ts:630-660). Codex threads share a long lived session, so that fits the Codex approvals staying pending after the cancel. I haven't traced why the Claude approval cleared.
None of the open pull requests around delegated cancel or approvals change this.
The same thing happens after t3_thread_interrupt, with a Claude child, and it is visible in the UI.
On 0.1.2-nightly.20261021.3473 (macOS desktop), a Claude delegated child (full access) stopped on a command approval. The parent interrupted it and sent new instructions with t3_thread_send. Run 3 started and worked normally: new tool calls and renders, no new approval. The child thread still reported pendingRequestCount: 1, and the "Subagent needs approval" banner stayed on screen for the old, interrupted run. The user reported it as a new request twice.
Related: #22925 (the parent agent gets no notice when a delegated child waits for an approval).
Verified the state regression on main snapshot 3b95e78: both interrupted terminal paths leave the approval pending; the completed-turn control passes. Existing fix #22023 now includes the main merge and has the bugfix label. Three focused suites pass 63 tests; targeted lint and server typecheck pass. Fresh client interaction proof remains incomplete after VM stalls and environment registration failures; the PR lists unverified surfaces. No merge performed.
Additional evidence from a Windows desktop Claude thread on T3 Code 0.1.3: the stale-approval state also occurs after the user presses Stop directly, without delegated-task cancellation.
The user stopped a run while a command approval was pending. The run was shown as interrupted, but the approval card and Approval badge remained. The user reported that Approve, Decline, Cancel, and Always allow this session could not dismiss it. Resume Thread also failed with This thread can no longer be resumed from that run.
Persisted state and timeline
A read-only SQLite audit found one pending command approval belonging to run 12 and its interrupted provider turn:
Record
State
Run, run attempt, and provider turn
interrupted
Command execution item
interrupted
Approval request
pending, with no resolved timestamp
Approval node and timeline item
waiting
Approval response capability
live
Session row
present, marked ready
Binding from that session to this thread
absent
Relevant timestamps on 2026-10-28, UTC:
17:34:09.523 Command approval created
17:34:35.617 Outgoing query.interrupt
17:34:35.618 Outgoing query.close
17:34:36.078 Provider turn becomes interrupted
17:34:36.088 Run becomes interrupted
17:34:36.599 thread.runtime-mode.set starts; trace result: Success
17:34:36.626 Resume message.dispatch starts; trace result: rejection
17:34:36.657 Session detach effect created: Runtime mode changed.
17:34:40.257 Session detach effect completes successfully
17:34:40.467 Approval response fails: Provider session <session> was not found.
17:34:42.326 Same approval response failure
17:36:09.384 Same approval response failure
17:37:38.460 Same Resume rejection
The session row was not deleted. The response-context query joins sessions to thread bindings, so the missing binding makes that session unavailable to the approval handler. The subsequent mode-change detach is a separate part of this sequence; the evidence does not attribute the missing binding directly to Stop.
There is also a related detach cleanup omission: when the last exclusive thread is detached, it is removed from the attachment set before the session and pending-request cleanup iterate that set. This helps explain why the later detach did not retire this already-stale request. ProviderSessionManager.
Source diagnosis on 0.1.3
Reviewed tag v0.1.3, commit d2c440312e5f39d59827ed466838a623516454d6:
Both terminal provider-event paths call question-only cleanup. The underlying query filters for kind = 'user_input', excluding command approvals. ProviderEventIngestor, ProjectionStore.
Stop's follow-up only calls settleInterruptedRun while the run is still running. That helper also returns if the run or attempt is already terminal, before reaching approval cancellation. This permits provider termination to win the ordering and leave approvals pending. Orchestrator.
The existing interrupted-turn test explicitly preserves its command approval fixture. The expected behavior needs updating as part of the regression coverage. ProviderEventIngestor test.
The ordering is supported by code and matches the incident's persisted state; a fresh provider-level reproduction was not run. The read-only audit checks the existing inconsistency, not the Stop implementation end to end.
The question-only terminal cleanup and the already-terminal Stop guards also remain in main inspected at 886d8f681234e3d88e30e0fd803fe9ccb13b0daf. PR #22023 was still open when checked; its reported test results are separate from this triage's checks.
Impact and regression coverage
The screenshot confirms stale attention and approval controls. Source inspection also shows that feedback to this approval, Settle, and Snooze depend on resolving the pending request; those additional actions were not exercised on the live thread. This is not a claim that all possible continuation paths are permanently blocked or that conversation history was lost.
Please include direct desktop Stop with Claude alongside delegated cancellation, both interrupted terminal-event shapes, multiple pending approvals, and concurrent approval responses. Cleanup should update request, node, timeline item, and response capability together while preserving other turns, already resolved decisions, and asynchronous message-mode questions. Normal root completion can leave legitimate background work, so it needs a separate control case.
This supports #21935 and its proposed fix #22023. The client offering an ineligible Resume action is being prepared as a separate report. No repair, provider command, or database write was performed during triage.
Environment: Windows 11, build 10.0.26200, T3 desktop with local server 0.1.3, Claude Agent SDK provider, Claude Opus 5.5. Triage CLI version was 0.1.2-nightly.20261022.3541, distinct from the affected server version.
Prepared by Codex, GPT-6, via t3 triage, with review by 10 dedicated agents.
Pi variant of this, with a worse side effect: the Pi process itself stays alive.
T3 Code 0.1.5 desktop (macOS), Pi 1.4.0. An auto-mode Claude parent delegated a task to the Pi provider. T3 runs Pi as approval-required in that case, so the child stopped on its first bash approval. The parent called task_cancel and got cancel_requested.
The pi --mode rpc process for that child was still running 25 minutes later, apparently still blocked in the extension's ctx.ui.confirm. It exited only when killed by hand. So for Pi, cancellation leaves a live provider process holding the pending confirm, on top of the stale approval record. Expected: cancelling the run aborts the pending confirm (Pi's ctx.signal) and ends the Pi process, or at least its turn.
Activity
juliusmarminge commentedon Oct 19, 2026
Note
Grok responding on behalf of Julius.
Thanks for flagging the difference between the two providers. Current main explains it.
When a provider turn ends, including when it is interrupted, the server only withdraws pending user input requests. The query that finds them is limited to that kind (
apps/server/src/orchestration-v2/ProjectionStore.ts:4429-4437;apps/server/src/orchestration-v2/ProviderEventIngestor.ts:579-585,:680-681). Pending approvals are only released when the whole provider session closes or fails (apps/server/src/orchestration-v2/ProviderSessionManager.ts:630-660). Codex threads share a long lived session, so that fits the Codex approvals staying pending after the cancel. I haven't traced why the Claude approval cleared.None of the open pull requests around delegated cancel or approvals change this.
Accepting this as a bug.
pedrozimmermannsoares commentedon Oct 21, 2026
The same thing happens after
t3_thread_interrupt, with a Claude child, and it is visible in the UI.On
0.1.2-nightly.20261021.3473(macOS desktop), a Claude delegated child (full access) stopped on a command approval. The parent interrupted it and sent new instructions witht3_thread_send. Run 3 started and worked normally: new tool calls and renders, no new approval. The child thread still reportedpendingRequestCount: 1, and the "Subagent needs approval" banner stayed on screen for the old, interrupted run. The user reported it as a new request twice.Related: #22925 (the parent agent gets no notice when a delegated child waits for an approval).
juliusmarminge commentedon Oct 22, 2026
Verified the state regression on main snapshot 3b95e78: both interrupted terminal paths leave the approval pending; the completed-turn control passes. Existing fix #22023 now includes the main merge and has the bugfix label. Three focused suites pass 63 tests; targeted lint and server typecheck pass. Fresh client interaction proof remains incomplete after VM stalls and environment registration failures; the PR lists unverified surfaces. No merge performed.
luquibu commentedon Oct 28, 2026
Additional evidence from a Windows desktop Claude thread on T3 Code 0.1.3: the stale-approval state also occurs after the user presses Stop directly, without delegated-task cancellation.
The user stopped a run while a command approval was pending. The run was shown as interrupted, but the approval card and Approval badge remained. The user reported that Approve, Decline, Cancel, and Always allow this session could not dismiss it. Resume Thread also failed with
This thread can no longer be resumed from that run.Persisted state and timeline
A read-only SQLite audit found one pending command approval belonging to run 12 and its interrupted provider turn:
Relevant timestamps on 2026-10-28, UTC:
The session row was not deleted. The response-context query joins sessions to thread bindings, so the missing binding makes that session unavailable to the approval handler. The subsequent mode-change detach is a separate part of this sequence; the evidence does not attribute the missing binding directly to Stop.
There is also a related detach cleanup omission: when the last exclusive thread is detached, it is removed from the attachment set before the session and pending-request cleanup iterate that set. This helps explain why the later detach did not retire this already-stale request. ProviderSessionManager.
Source diagnosis on 0.1.3
Reviewed tag
v0.1.3, commitd2c440312e5f39d59827ed466838a623516454d6:kind = 'user_input', excluding command approvals. ProviderEventIngestor, ProjectionStore.settleInterruptedRunwhile the run is still running. That helper also returns if the run or attempt is already terminal, before reaching approval cancellation. This permits provider termination to win the ordering and leave approvals pending. Orchestrator.The ordering is supported by code and matches the incident's persisted state; a fresh provider-level reproduction was not run. The read-only audit checks the existing inconsistency, not the Stop implementation end to end.
The question-only terminal cleanup and the already-terminal Stop guards also remain in main inspected at
886d8f681234e3d88e30e0fd803fe9ccb13b0daf. PR #22023 was still open when checked; its reported test results are separate from this triage's checks.Impact and regression coverage
The screenshot confirms stale attention and approval controls. Source inspection also shows that feedback to this approval, Settle, and Snooze depend on resolving the pending request; those additional actions were not exercised on the live thread. This is not a claim that all possible continuation paths are permanently blocked or that conversation history was lost.
Please include direct desktop Stop with Claude alongside delegated cancellation, both interrupted terminal-event shapes, multiple pending approvals, and concurrent approval responses. Cleanup should update request, node, timeline item, and response capability together while preserving other turns, already resolved decisions, and asynchronous message-mode questions. Normal root completion can leave legitimate background work, so it needs a separate control case.
This supports #21935 and its proposed fix #22023. The client offering an ineligible Resume action is being prepared as a separate report. No repair, provider command, or database write was performed during triage.
Environment: Windows 11, build 10.0.26200, T3 desktop with local server 0.1.3, Claude Agent SDK provider, Claude Opus 5.5. Triage CLI version was 0.1.2-nightly.20261022.3541, distinct from the affected server version.
Prepared by Codex, GPT-6, via t3 triage, with review by 10 dedicated agents.
DamonYoungWork commentedon Oct 30, 2026
Pi variant of this, with a worse side effect: the Pi process itself stays alive.
T3 Code 0.1.5 desktop (macOS), Pi 1.4.0. An
auto-mode Claude parent delegated a task to the Pi provider. T3 runs Pi asapproval-requiredin that case, so the child stopped on its firstbashapproval. The parent calledtask_canceland gotcancel_requested.The
pi --mode rpcprocess for that child was still running 25 minutes later, apparently still blocked in the extension'sctx.ui.confirm. It exited only when killed by hand. So for Pi, cancellation leaves a live provider process holding the pending confirm, on top of the stale approval record. Expected: cancelling the run aborts the pending confirm (Pi'sctx.signal) and ends the Pi process, or at least its turn.