Skip to content

T3 tools fail with parent_not_active after a queued provider switch while the old provider has background work #37000

Open

Description

@Alb11747

Area

apps/server (orchestration-v2: ProviderSessionManager MCP credentials, queued provider hand-off)

Steps to reproduce

On main 1ba934798f, web dev app (vp run dev), fresh database. Uses Claude Haiku 5.5 and the free Replay (dev) provider. Any second provider works, since only its attach matters.

  1. New thread on Claude Haiku 5.5. Send:

    Call the T3 Code MCP tool orchestrator_capabilities once and report whether it succeeded. Then use the Bash tool with run_in_background set to true to run: sleep 600. Then use the Bash tool in the foreground to run exactly: python3 -c "import time; time.sleep(60)" and wait for it. Then reply DONE.

  2. While it shows "Running python3", pick Replay (dev) → Plan and reads, type hello, and press Ctrl/Cmd+Enter to queue it. The default Enter tries to steer and fails.
  3. Claude's turn ends with "Sleep 600 seconds in background" still running. The queued Replay turn runs as a context hand-off.
  4. Pick Claude Haiku 5.5 again and send:

    Call the T3 Code MCP tool orchestrator_capabilities, then call the T3 Code MCP tool delegate_task with target providerInstanceId devReplay and model showcase, task "Say hi", mode wait. Quote each call's exact result or error text.

  5. Press Stop on the background sleep row. Wait until the thread is idle; Claude may run a short turn about the stopped task. Send the step 4 message again.

Expected behavior

Step 4 runs normally, since no Claude model or setting changed, and delegate_task starts the child task, as it does when step 1 starts no background command.

Actual behavior

  • Step 4: Provider error: Claude is still running background agents or commands, and this model or setting change would end them. Wait for them to finish, or press Stop, then send the message again.
  • Step 5: orchestrator_capabilities succeeds, then delegate_task returns {"_tag":"OrchestratorMcpFailure","code":"parent_not_active","message":"The calling provider no longer owns an active thread run."}. The automatic turn's t3_background_wait also fails with parent_not_active. New turns do not recover.

This failed in 3 of 3 runs. With no background command in step 1, it passed (1 of 1).

Cause: queued dispatch deliberately keeps a busy session attached on a create_with_handoff switch ("A handoff runs in its own session, so a busy one stays up"; upstream's test refuses a later instance change while a retained hand-off session runs background work relies on this). Replay's attach runs prepareMcpSession, which calls revokeThread and overwrites the thread's single credential slot. Going back to Claude reuses its retained, still-attached session, so no credential is issued for Claude. Claude then reads the slot and gets a Replay-scoped token, which changes its query key (hence the step 4 error) and fails isLiveCallerShell (hence parent_not_active). A retained Codex session would keep the revoked token instead and get HTTP 401 "Authentication required" (seen in a test, not run live).

This is the case asked for in #36801: plain composer switching refuses while background work runs, but a queued switch does not. Related: #16565, #36453, #36801.

Impact

Agent orchestration (delegation, thread messaging, background waits) stays broken in that thread until the provider session is released, which takes the 30-minute idle timeout or longer while the session is pinned, or a server restart. The step 4 error also blames a model or setting change the user never made.

Version or commit

1ba934798f81d5d0d7852b9bbedb19b221704e07 (main, 2026-11-14)

Environment

Linux, web dev app via vp run dev, Claude Code 2.1.325 (Claude Haiku 5.5), Replay (dev) provider.

Logs or stack traces

Server trace for step 3: McpSessionRegistry.revokeThread then McpSessionRegistry.issue. The failing calls show tools/call delegate_task and tools/call t3_background_wait with error.type: tool_error. The provider event log has the tool_result above. No server-side warning is logged.

An orchestration-level test (real Orchestrator, EffectWorker and ProviderSessionManager, fake adapters, a credential-recording registry) shows both orders, Claude → Codex → Claude and Codex → Claude → Codex. A busy retained session ends with its credential revoked, and no credential is issued on the return. The idle controls get a fresh credential. The patch is available on request.

Workaround

Restart the server, or wait for the retained session's idle release. Avoid queueing a message on another provider while the current provider has background work.


Posted by Claude Opus 5.5 on behalf of Alb11747.

Activity

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