Summary
sessions_spawn (subagent spawn) persists the raw canonical provider (anthropic) into the child session entry instead of resolving it to the configured CLI runtime (claude-cli). For depth-2 spawns with no cached CLI session binding, the child run registers, never launches a CLI process, and dies 30 minutes later when the sweeper reaps it:
"outcome": { "status": "error", "error": "subagent run lost active execution context" }
"endedReason": "subagent-error"
This is another unaddressed call-site of the regression family tracked in #57326 — the same missing resolveCliRuntimeExecutionProvider call that has now been fixed in the queued-followup path (#82857), cron executor, attempt-execution, and agent-runner.runtime. The two spawn dispatchers were never patched.
Both files verified still unpatched on current main (checked 2026-06-12) and in the released 2026.6.5 dist.
Environment
- OpenClaw 2026.6.5 (5181e4f), Linux arm64
- CLI-backed runtime:
agents.defaults.models["anthropic/..."].agentRuntime.id = "claude-cli", auth profile anthropic:claude-cli (OAuth)
- Agent models use canonical refs (
anthropic/claude-...), per the documented config pattern
Live evidence on 2026.6.5 — even successful spawns report the unresolved provider
Every sessions_spawn ack on 2026.6.5 returns the raw provider:
{
"status": "accepted",
"resolvedModel": "anthropic/claude-...",
"resolvedProvider": "anthropic", // ← never "claude-cli", even when claude-cli runs it
"modelApplied": true
}
Depth-1 spawns still work because agent-runner.runtime repairs the provider downstream. Depth-2 spawns hit the unrepaired window (below) and intermittently die.
Smoking gun — single-field diff between working and failing spawns
Same agent (planner), same model, same config, same depth=2, same day:
| session |
persisted modelProvider |
cliSessionBindings |
result |
| run A |
claude-cli |
present |
✅ ran 9.2 min, transcript 11 KB, done |
| run B |
anthropic |
absent |
❌ silent 31.5 min, empty transcript, "lost execution context" |
| run C (auto-retry) |
anthropic |
absent |
❌ identical |
The only persisted difference is whether the provider got resolved. When a previous spawn left a cached CLI session binding, downstream reuse masks the bug; a cold spawn (no binding) launches nothing and is swept at +30 min (sweepStaleRunContexts, maxAgeMs=1800s). That cache-masking is why the failure looks intermittent and why it has been hard to pin down.
Root cause (current main, verified at source)
Call site 1 — src/agents/subagent-spawn.ts
The file (1,773 lines) contains zero imports of resolveCliRuntimeExecutionProvider. The child session entry is persisted with the raw split of the model ref:
// src/agents/subagent-spawn.ts:364-388 (persistInitialChildSessionRuntimeModel)
const { provider, model } = splitModelRef(params.resolvedModel); // "anthropic"
...
store[target.canonicalKey] = mergeSessionEntry(store[target.canonicalKey], {
model,
...(provider ? { modelProvider: provider } : {}), // ← persists RAW "anthropic"
});
buildResolvedSubagentModelMetadata (line 288) reports the same raw value back to the caller — which is exactly the "resolvedProvider": "anthropic" we see in every spawn ack.
Call site 2 — src/gateway/server-methods/agent.ts
The handler (2,848 lines) also has zero resolver imports. Provider flows raw end-to-end:
// line 1120
const providerOverride = allowModelOverride ? request.provider : undefined;
// line 1422
const effectiveProvider = providerOverride || baseProvider;
// line 2350 — reads back the session entry that call site 1 persisted raw
const activeModelProvider =
providerOverride ??
resolveSessionModelRef(cfgForAgent ?? cfg, sessionEntry, activeSessionAgentId).provider;
// line ~2540 — dispatches with the raw provider
dispatchAgentRunFromGateway({ ingressOpts: { provider: providerOverride, ... } });
Why depth 2 is the victim
The run is registered (registerSubagentRun) before agent-runner.runtime's own resolver fires. Depth-1 spawns from a live main session go through reply-path admission that resolves the runtime independently. Depth-2 spawns (subagent → subagent) depend entirely on the session entry persisted by call site 1 — which holds modelProvider: "anthropic". With no cached CLI binding to fall back on, the launch path tries to honor a provider that is not an executable runtime, silently no-ops, and the sweeper declares "lost execution context" 30 minutes later. Empty transcript, zero tokens, parent pipeline stalls. Related symptom reports: #77720, #47975.
Proposed fix — same pattern as the merged #82857
src/auto-reply/reply/followup-runner.ts:808-823 is the maintainer-accepted template:
const cliExecutionProvider =
(sessionRuntimeOverride && isCliProvider(sessionRuntimeOverride, runtimeConfig)
? sessionRuntimeOverride
: undefined) ??
resolveCliRuntimeExecutionProvider({
provider, cfg: runtimeConfig, agentId: run.agentId,
modelId: model, authProfileId: selectedAuthProfile.authProfileId,
}) ??
provider;
Apply it at both unpatched sites:
1. subagent-spawn.ts — resolve before persisting (in persistInitialChildSessionRuntimeModel, or at its call site where cfg and the target agent id are in scope):
import { resolveCliRuntimeExecutionProvider } from "./model-runtime-aliases.js";
const { provider: rawProvider, model } = splitModelRef(params.resolvedModel);
const provider = rawProvider
? (resolveCliRuntimeExecutionProvider({
provider: rawProvider,
cfg: params.cfg,
agentId: params.agentId, // needs the target agent id threaded in
modelId: model,
}) ?? rawProvider)
: rawProvider;
This makes the child session entry carry the executable runtime (claude-cli) from the moment it exists — closing the registration→runner window for every depth, and fixing the misleading resolvedProvider in the spawn ack as a side effect.
2. server-methods/agent.ts — resolve activeModelProvider before run registration (line ~2350):
const rawActiveModelProvider =
providerOverride ??
resolveSessionModelRef(cfgForAgent ?? cfg, sessionEntry, activeSessionAgentId).provider;
const activeModelProvider =
resolveCliRuntimeExecutionProvider({
provider: rawActiveModelProvider,
cfg: cfgForAgent ?? cfg,
agentId: activeSessionAgentId,
}) ?? rawActiveModelProvider;
resolveCliRuntimeExecutionProvider returns undefined for non-CLI providers (src/agents/model-runtime-aliases.ts:232), so both changes are no-ops for embedded/API-backed setups — only configs with a CLI runtime mapping are affected.
Acceptance criteria
- Depth-2 cold spawn (no prior CLI session binding for the target agent) with a canonical
anthropic/... model on a claude-cli runtime: child launches a CLI process and produces a transcript.
- Child session entry persists
modelProvider: "claude-cli" (or the configured CLI runtime) — never the raw canonical provider — when a CLI runtime is configured.
- Spawn ack
resolvedProvider reflects the execution runtime.
- No behavior change when no CLI backend is configured (resolver returns
undefined → falls back to raw provider).
Repro
- Configure a model with a CLI runtime (e.g.
agents.defaults.models["anthropic/claude-sonnet-4-6"].agentRuntime.id = "claude-cli"), maxSpawnDepth >= 2.
- Spawn agent A from the main session; have A
sessions_spawn agent B (mode: "run") — B must be an agent with no prior CLI session binding (fresh install or wipe cliSessionBindings).
- Observe: B registers, no CLI process starts, transcript stays empty, and after ~30 min the run fails with
subagent run lost active execution context.
- Inspect B's session entry:
modelProvider: "anthropic", no claudeCliSessionId, no cliSessionBindings — the signature.
Relationship to existing reports
Summary
sessions_spawn(subagent spawn) persists the raw canonical provider (anthropic) into the child session entry instead of resolving it to the configured CLI runtime (claude-cli). For depth-2 spawns with no cached CLI session binding, the child run registers, never launches a CLI process, and dies 30 minutes later when the sweeper reaps it:This is another unaddressed call-site of the regression family tracked in #57326 — the same missing
resolveCliRuntimeExecutionProvidercall that has now been fixed in the queued-followup path (#82857), cron executor,attempt-execution, andagent-runner.runtime. The two spawn dispatchers were never patched.Both files verified still unpatched on current main (checked 2026-06-12) and in the released
2026.6.5dist.Environment
agents.defaults.models["anthropic/..."].agentRuntime.id = "claude-cli", auth profileanthropic:claude-cli(OAuth)anthropic/claude-...), per the documented config patternLive evidence on 2026.6.5 — even successful spawns report the unresolved provider
Every
sessions_spawnack on 2026.6.5 returns the raw provider:{ "status": "accepted", "resolvedModel": "anthropic/claude-...", "resolvedProvider": "anthropic", // ← never "claude-cli", even when claude-cli runs it "modelApplied": true }Depth-1 spawns still work because
agent-runner.runtimerepairs the provider downstream. Depth-2 spawns hit the unrepaired window (below) and intermittently die.Smoking gun — single-field diff between working and failing spawns
Same agent (
planner), same model, same config, same depth=2, same day:modelProvidercliSessionBindingsclaude-clianthropicanthropicThe only persisted difference is whether the provider got resolved. When a previous spawn left a cached CLI session binding, downstream reuse masks the bug; a cold spawn (no binding) launches nothing and is swept at +30 min (
sweepStaleRunContexts, maxAgeMs=1800s). That cache-masking is why the failure looks intermittent and why it has been hard to pin down.Root cause (current main, verified at source)
Call site 1 —
src/agents/subagent-spawn.tsThe file (1,773 lines) contains zero imports of
resolveCliRuntimeExecutionProvider. The child session entry is persisted with the raw split of the model ref:buildResolvedSubagentModelMetadata(line 288) reports the same raw value back to the caller — which is exactly the"resolvedProvider": "anthropic"we see in every spawn ack.Call site 2 —
src/gateway/server-methods/agent.tsThe handler (2,848 lines) also has zero resolver imports. Provider flows raw end-to-end:
Why depth 2 is the victim
The run is registered (
registerSubagentRun) beforeagent-runner.runtime's own resolver fires. Depth-1 spawns from a live main session go through reply-path admission that resolves the runtime independently. Depth-2 spawns (subagent → subagent) depend entirely on the session entry persisted by call site 1 — which holdsmodelProvider: "anthropic". With no cached CLI binding to fall back on, the launch path tries to honor a provider that is not an executable runtime, silently no-ops, and the sweeper declares "lost execution context" 30 minutes later. Empty transcript, zero tokens, parent pipeline stalls. Related symptom reports: #77720, #47975.Proposed fix — same pattern as the merged #82857
src/auto-reply/reply/followup-runner.ts:808-823is the maintainer-accepted template:Apply it at both unpatched sites:
1.
subagent-spawn.ts— resolve before persisting (inpersistInitialChildSessionRuntimeModel, or at its call site wherecfgand the target agent id are in scope):This makes the child session entry carry the executable runtime (
claude-cli) from the moment it exists — closing the registration→runner window for every depth, and fixing the misleadingresolvedProviderin the spawn ack as a side effect.2.
server-methods/agent.ts— resolveactiveModelProviderbefore run registration (line ~2350):resolveCliRuntimeExecutionProviderreturnsundefinedfor non-CLI providers (src/agents/model-runtime-aliases.ts:232), so both changes are no-ops for embedded/API-backed setups — only configs with a CLI runtime mapping are affected.Acceptance criteria
anthropic/...model on aclaude-cliruntime: child launches a CLI process and produces a transcript.modelProvider: "claude-cli"(or the configured CLI runtime) — never the raw canonical provider — when a CLI runtime is configured.resolvedProviderreflects the execution runtime.undefined→ falls back to raw provider).Repro
agents.defaults.models["anthropic/claude-sonnet-4-6"].agentRuntime.id = "claude-cli"),maxSpawnDepth >= 2.sessions_spawnagent B (mode: "run") — B must be an agent with no prior CLI session binding (fresh install or wipecliSessionBindings).subagent run lost active execution context.modelProvider: "anthropic", noclaudeCliSessionId, nocliSessionBindings— the signature.Relationship to existing reports