Skip to content

[Bug]: Thread-bound MCP tools fail with parent_not_active after a Claude thread's compaction and process restart, until the server restarts #19308

Open

Description

@kaankolcu

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

  1. Run a long Claude Code coordinator thread in the desktop app that uses orchestration tools (delegate_task, t3_thread_launch, link_pull_request).
  2. Let the thread go through a context compaction and a Claude Code process restart. The thread then gets a "Provider context handoff" item, and its provider thread shows as pending:run:....
  3. Call any thread-bound tool from that thread, in that turn or in later user turns.

Expected behavior

The thread's next run owns its MCP session again, so thread-bound tools work without a server restart.

Actual behavior

Every thread-bound tool fails with:

{"_tag":"OrchestratorMcpFailure","code":"parent_not_active","message":"The calling provider no longer owns an active thread run."}

This hit delegate_task, t3_thread_launch, link_pull_request, html_render and preview_open, across several user turns over about 3 hours. Tools that are not thread-bound kept working (t3_environment_read, orchestrator_capabilities). A new user message did not clear it. The provider instance did not change, unlike #16565, and no scheduled task was involved, unlike #17932.

Impact

A coordinator cannot delegate, launch threads, link PRs or render pages until someone restarts the T3 server.

Version or commit

0.0.46-nightly.20261013.3066

Environment

macOS, desktop app with its built-in server, Claude Code provider.

Logs or stack traces

The error above. No server logs collected.

Workaround

Restart the T3 server. Right after the restart, t3_thread_launch, delegate_task and link_pull_request all succeeded from the same thread.

Activity

  1. juliusmarminge commented on Oct 14, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Thanks for the detailed report. Before we treat this as a new bug, here's what I found on main, and I need a couple of things from you.

    What the check does. parent_not_active comes from assertLiveCaller in apps/server/src/mcp/threadAccess.ts. It rejects a call in only three cases:

    1. the thread is archived,
    2. the thread has no activeRunId, or
    3. the thread's providerInstanceId doesn't match the provider instance the MCP credential was issued for (scope.thread.providerInstanceId).

    Nothing in that check looks at compaction, the "Provider context handoff" item or the pending:run:... provider thread id directly. So one of those three conditions has to have been true for about 3 hours, and a server restart cleared it, which fits a stale in-memory credential scope.

    Known causes. Condition 3 is the same failure as #16565 (a credential scoped to an old provider after a reused session skips prepareMcpSession), which open PR #17096 fixes. #17932/#18467 (scheduled tasks) and #16808/#19237 (background subagents after the turn settles) are the other known ways to get there. You've ruled out a provider switch and scheduled tasks, but a Claude process restart that resumes on a session ensureThreadAttached already treats as attached would hit the same stale credential path as #16565 without a provider change. I can't confirm that from code alone.

    Could you:

    1. Retest on v0.0.46-nightly.20261014.3093 (it includes fix(server): repair ownership UUID generation #19298, a fix to how ownership UUIDs are generated).
    2. If it happens again, before restarting, share the server log lines around the compaction/restart (look for McpSessionRegistry.issue, prepareMcpSession and the run start), plus the thread's row in the provider session bindings (provider instance ids listed for that thread).
    3. Say whether any background subagent or delegated task from that thread was still running when the errors started.

    If the logs show the credential wasn't reissued for the restarted Claude process, I'll fold this into #16565. Restarting the server remains the workaround.

  2. kaankolcu commented on Oct 14, 2026

    @kaankolcu
    Author

    Follow-up with the data you asked for. I was wrong in the report: a scheduled task and a provider switch were both involved.
    This looks like #17932 leading to #16565, with compaction as the step that re-reads the slot.

    • The coordinator thread is on claudeAgent_claude_mas. A thread-bound interval task created earlier on claudeAgent_personal2
      (dev-reingest-heartbeat, model_selection.instanceId = claudeAgent_personal2) kept firing at :37 each hour and ran single runs on personal2.
    • 20:37:25Z: heartbeat run on personal2 (fresh personal2 session, so prepareMcpSession(thread, personal2) minted the thread slot).
      The claude_mas session stayed alive.
    • 20:53:58Z: manual compaction on claude_mas (query.close then query.open in the same provider session). ClaudeAdapterV2.openQuery
      reads mcpSessions.read(threadId) (ClaudeAdapterV2.ts:8276 at 20261013.3066). That returned the personal2 credential. No
      prepareMcpSession ran, because open took the reuse path (ProviderSessionManager.ts:2050-2066).
    • From 20:57Z, every gated tool failed with parent_not_active (condition 3: credential instance personal2, thread instance claude_mas). An active run
      existed during the failures (for example run 569, 05:45:59-05:49:07Z). Ungated reads on the same token worked, so the token was valid.
      A second query reopen at 22:51:55Z and a new user turn at 05:42Z did not help. The server restart at 07:57Z fixed it.
    • The same thing happened earlier at 15:37Z: a personal2 heartbeat run, then a claude_mas query reopen at 15:37:59Z, then failures until the 16:04Z restart.
    • Provider session bindings for the thread: claudeAgent_claude_mas:…:bb352512, claudeAgent_personal2:…:8a077c8f, claudeAgent_claude2:…:1e39d810.
    • No background subagent was involved in the failing calls. They came from the root turn.

    Suggestion beyond #17096 and #18467: the Claude adapter should check that the slot's providerInstanceId equals its own session's
    instance before using it in openQuery (or run prepareMcpSession on every query reopen). Otherwise any other-instance turn on the thread
    breaks a still-live session the next time it compacts. Happy to close this as a duplicate of #16565/#17932.

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

    needs more infoInitial triage showed no bug. Awaiting more infovia-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions