Skip to content

Approval-pending commands stay "Running" after a runtime-mode change fails their run #22957

Closed

Description

@SimonLiu423

What happened

In a Claude thread, after the agent finished its task, the composer still shows "Running 2 commands mkdir -p /tmp/sysmon && cd /tmp/sysmon && for i in $(seq 1 1…" with a Stop button. Nothing is running: the commands ran and finished in a later run of the same thread, and no matching process exists on the machine. The banner stays.

Diagnosis

The two commands belong to a run that was closed by a runtime-mode change while their approvals were still pending. Their turn items were never terminalized, so they stay running forever.

Timeline (UTC) from the thread's provider event log, server trace and the state database:

  1. 14:58:46 / 14:58:48. Run 1 (Supervised) emits two Bash tool_use blocks. Each opens an approval runtime request, and each gets a command_execution turn item with status running.
  2. 14:58:49.226. While both approvals are pending, the user switches the thread to Auto (thread.runtime-mode.set) and sends a message (message.dispatch, 14:58:49.269).
  3. 14:58:49.528. The Claude query is closed (query.close), and run 1 is finalized as failed (completedAt 14:58:49.529Z). A new query resumes the session and run 2 starts.
  4. 14:58:50.906. The client's runtime-request.respond for the stale approval fails: RuntimeRequestService.respond → ProviderAdapterRuntimeRequestResponseError: Failed to respond to claudeAgent runtime request …. The runtime request rows end up resolved.
  5. In run 2, Claude re-issues both commands (new tool-use ids), and they complete normally. Run 2 completes at 15:02:36.

Final DB state for run 1: run failed, but its two command_execution items (toolu_01NnYJ…, toolu_01KHp5…) remain status = running, completedAt = null.

Why the banner shows them: selectShellPendingTurnItemRows (apps/server/src/orchestration-v2/ProjectionStore.ts ~L5858 at v0.1.1) returns every command_execution / dynamic_tool / subagent item with a non-terminal status. It excludes only items whose run is rolled_back, so items of a failed run are still reported as pending shell work.

Why they are never settled: writeFinalRunEvents (apps/server/src/orchestration-v2/RunExecutionService.ts ~L615) cascades terminal status to run-owned subagents (cascadeTerminalizeRunOwnedSubagents) but not to the run's command items. Leaving those open is presumably deliberate for real run_in_background shells, which can outlive their run. But these items never started: they were still awaiting approval when the run ended, so nothing will ever complete them.

A likely fix direction: when a run reaches a terminal status, terminalize (as interrupted or cancelled) its command and dynamic-tool items that were never started or were only awaiting approval, while leaving confirmed background tasks alone. Alternatively, the pending-shell query could ignore non-background items whose run is terminal.

Steps to reproduce

  1. Desktop app, Claude provider, thread in Supervised (approval-required) runtime mode.
  2. Ask for something that makes Claude issue two Bash tool calls in one assistant message (e.g. "monitor my system's CPU for 3 minutes").
  3. While both approval requests are pending, switch the composer's runtime mode to Auto and send a message ("just gave you auto access").
  4. Let the new run finish.
  5. Observe: the "Running 2 commands …" banner with Stop stays above the composer. In orchestration_v2_projection_turn_items, the first run's two command_execution items are still running while the run is failed.

(Reproduced once from logs, not yet re-run deliberately.)

Version

T3 Code (Beta) desktop app, server 0.1.1 (local server started ~8h before the bug; the triage CLI was also 0.1.1)

Environment

macOS 27.0.1 (darwin arm64, Apple M1), Node v26.8.2, Claude Code 2.1.306, model claude-opus-5-5

Evidence

# orchestration_v2_projection_runs
run …:ordinal:1  claudeAgent  failed     requested 14:58:31.453Z  completed 14:58:49.529Z
run …:ordinal:2  claudeAgent  completed  requested 14:58:49.569Z  completed 15:02:36.357Z

# orchestration_v2_projection_turn_items (command_execution, run 1)
toolu_01Qs4gEmhvBZoHSxnWa9g1s3  completed  14:58:41.434Z
toolu_01NnYJERtKBvD4EJMDtFCEDd  running    14:58:46.035Z  completedAt=null   # mkdir -p /tmp/sysmon && … top … sleep 7
toolu_01KHp53LQDsorpQz6k2fqFEx  running    14:58:48.070Z  completedAt=null   # ps -p … ; sysctl vm.swapusage …

# provider event log
14:58:48.079Z  incoming  message_delta stop_reason=tool_use
14:58:49.528Z  outgoing  query.close
14:58:50.283Z  outgoing  query.open  permissionMode=auto resume=<same session>
14:58:50.284Z  outgoing  prompt.offer "just gave you auto access"

# server trace
14:58:49.226  orchestrationV2.dispatch.once  thread.runtime-mode.set  Success
14:58:49.271  orchestrationV2.dispatch.once  message.dispatch         Success
14:58:50.902  orchestrationV2.dispatch.once  runtime-request.respond  Success
14:58:50.906  RuntimeRequestService.respond            Failure  RuntimeRequestResponseExecutionError: Failed to respond to runtime request runtime-request:provider:claudeAgent:…
14:58:50.907  ClaudeAdapterV2.respondToRuntimeRequest  Failure  ProviderAdapterRuntimeRequestResponseError: Failed to respond to claudeAgent runtime request …

Related issues

#16000 (runtime-mode change detaches the Claude session without the background-work check): the same trigger, but that issue is about killing live background work, not about approval-pending items left running. #16557 (failed run leaves the provider turn running): the same family (failure finalization doesn't terminalize child rows), but a different row type. #18188 ("Running" banner where Stop does nothing): there, the server already had the item completed and the client copy was stale; here, the server itself has it running. #21503 (send declines pending approvals) is web/mobile only and does not cover the runtime-mode detach path.

Fix applied or workaround

None applied. The banner is cosmetic; starting a new thread avoids it.

Filed by

Claude Code (claude-opus-5-5) via t3 triage

Activity

  1. psicilia5179 commented on Oct 25, 2026

    @psicilia5179

    Also hitting this on 0.1.2 (Windows desktop app with its local server, plus the iOS app; claudeAgent / claude-opus-5-5). Details are in #25054, which was closed as a duplicate of this one. What it adds:

    • Supervised → Full access triggers it the same way as → Auto. The provider log shows query.close, then query.open with permissionMode: "bypassPermissions" and the same resume session.
    • MCP tools as well as Bash. For a stuck mcp__claude-in-chrome__navigate, the leftover item is a dynamic_tool, and the pill reads "Waiting on background task Navigate".
    • Frequency. Six occurrences in three days of normal use, every time the user answered an approval by switching the mode and typing "approved, you have full access". Each one shows the same sequence within about 50 ms: decline → run failed → new run.
    • Stale approval cards stay answerable. Cards for dead tool calls keep working buttons. That includes one from a plain steer, where the tool item itself was closed correctly. Tapping a card resolves the dead request, the agent never sees it, and the stuck item stays running. During a later Full access run, an old card looked like that run's own prompt.
    • The sidebar shows the thread as Waiting the whole time, as well as the composer pill.

    Workaround: tap Allow or Decline first, then change the mode.

  2. Chinoman10 commented on Nov 6, 2026

    @Chinoman10
    Contributor

    Confirmed the same runtime-mode-change failure family on T3 0.1.7-derived build 0.1.7-owner-credentials.2, Linux x64, using the Pi provider (Pi 1.5.0) on 2026-11-06. This is a locally patched build, not a clean stock-0.1.7 reproduction.

    A side-chat was waiting for a tool approval when its permission mode changed. The provider session was detached, the active turn failed, and the approval remained pending against the removed session:

    15:21:33.808 UTC  tool approval pending
    15:21:38.467 UTC  provider event ingestion failed
      ProviderAdapterEventStreamError
      caused by: Error: Runtime mode changed.
    subsequent approval response:
      Provider session … was not found.
    

    The conversation was recoverable by starting a follow-up turn, but retrying the old approval could not deliver to the dead session. This adds Pi evidence to the runtime-mode detach/approval symptoms reported here and in #16000; it does not claim the exact two-Claude-command banner reproduction.

    Our installed 0.1.7 code still has the eager thread.runtime-mode.set detach for providers without in-session switching. We are testing a local backport of #23082 separately; this comment confirms the observed failure, not a fix or production rollout.

    Posted with GPT-6.1 Sol through Pi in T3 Code, at the user's request.

  3. josephv123 commented on Nov 10, 2026

    @josephv123
    Contributor

    Note

    Claude Opus 5.5 in Claude Code, writing on behalf of @josephv123.

    Another trigger for the same leftover: a provider switch, with no approval involved. On 0.1.9-nightly.20261110.4478 (Linux x64, headless server, viewed from the macOS desktop app), the stuck item is a dynamic_tool that had already started running.

    What happened (UTC, 2026-11-10)

    1. A thread on the cursor instance (model claude-opus-5-5) was asked to move itself and its child thread back to claudeAgent.
    2. 16:41:41. It called t3_thread_configure on the child thread. That call completed.
    3. 16:41:42.455. It called t3_thread_configure on its own thread (modelSelection: {instanceId: "claudeAgent", model: "claude-opus-5-5", ...}). The switch went through.
    4. 16:41:42.564. The switch detached the Cursor session mid-call, so the run failed with "The provider event stream closed unexpectedly." That part is Switching a thread's provider instance during a running turn kills the turn with "provider event stream closed unexpectedly" #22748.
    5. The run is failed, but the second t3_thread_configure item is still status: running with no completion (t3_thread_read activity shows it). The app shows "Waiting · mcp__t3-code__t3_thread_configure" with a timer counting from 16:41 (2h 54m by 19:36) and a Stop button. Later runs on claudeAgent completed normally underneath it.

    So beyond the approval case in the original report, the never-terminalized items also include a dynamic_tool call that was mid-flight when its own provider session was detached. It's a plain MCP call, not a background task, so nothing will ever complete it. Terminalizing a failed run's non-background dynamic_tool and command_execution items, as suggested above, would cover this too.

  4. juliusmarminge commented on Nov 12, 2026

    @juliusmarminge
    Member

    Fixed by #29036, now on main: After switching a Claude thread from Supervised to Auto while command approvals are pending, the released session’s unfinished commands are now marked interrupted, so they no longer leave the composer showing Running commands after the next turn completes; existing historical rows are not repaired on upgrade.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions