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]: Thread-bound MCP tools fail with parent_not_active after a Claude thread's compaction and process restart, until the server restarts #19308
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
Run a long Claude Code coordinator thread in the desktop app that uses orchestration tools (delegate_task, t3_thread_launch, link_pull_request).
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:....
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.
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:
the thread is archived,
the thread has no activeRunId, or
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.
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).
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.
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.
Activity
juliusmarminge commentedon Oct 14, 2026
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_activecomes fromassertLiveCallerinapps/server/src/mcp/threadAccess.ts. It rejects a call in only three cases:activeRunId, orproviderInstanceIddoesn'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 sessionensureThreadAttachedalready 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:
v0.0.46-nightly.20261014.3093(it includes fix(server): repair ownership UUID generation #19298, a fix to how ownership UUIDs are generated).McpSessionRegistry.issue,prepareMcpSessionand the run start), plus the thread's row in the provider session bindings (provider instance ids listed for that thread).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.
kaankolcu commentedon Oct 14, 2026
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.
claudeAgent_claude_mas. A thread-bound interval task created earlier onclaudeAgent_personal2(
dev-reingest-heartbeat,model_selection.instanceId = claudeAgent_personal2) kept firing at :37 each hour and ran single runs onpersonal2.personal2(freshpersonal2session, soprepareMcpSession(thread, personal2)minted the thread slot).The
claude_massession stayed alive.claude_mas(query.closethenquery.openin the same provider session).ClaudeAdapterV2.openQueryreads
mcpSessions.read(threadId)(ClaudeAdapterV2.ts:8276at20261013.3066). That returned thepersonal2credential. NoprepareMcpSessionran, becauseopentook the reuse path (ProviderSessionManager.ts:2050-2066).parent_not_active(condition 3: credential instancepersonal2, thread instanceclaude_mas). An active runexisted 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.
personal2heartbeat run, then aclaude_masquery reopen at 15:37:59Z, then failures until the 16:04Z restart.claudeAgent_claude_mas:…:bb352512,claudeAgent_personal2:…:8a077c8f,claudeAgent_claude2:…:1e39d810.Suggestion beyond #17096 and #18467: the Claude adapter should check that the slot's
providerInstanceIdequals its own session'sinstance before using it in
openQuery(or runprepareMcpSessionon every query reopen). Otherwise any other-instance turn on the threadbreaks a still-live session the next time it compacts. Happy to close this as a duplicate of #16565/#17932.