Upstream Bug 2 — sessions_spawn returns modelApplied: true while actually running a stale resumed model
Repo: github.com/openclaw/openclaw
Suggested labels: bug, gateway, sessions, correctness
OpenClaw version: 2026.4.5
Severity: High — silent model substitution with no visible signal to the orchestrator
Title
sessions_spawn with explicit model argument silently resumes a stale session and runs on the cached model, but the spawn response still reports modelApplied: true
Summary
When spawning a subagent with an explicit model argument, the gateway appears to resume an existing session entry for that agent (matching by agentId) instead of creating a fresh session. The resumed session can have a stale model cached in its persisted state — meaning the subagent runs on the wrong model while the spawn response cheerfully reports modelApplied: true.
Two distinct problems:
- Routing bug: Explicit
model argument is not honored when a stale session entry exists.
- Reporting bug:
modelApplied: true is set based on whether the gateway intended to apply a model, not on whether the actual inference used the requested one.
Environment
openclaw@2026.4.5
- macOS 14, Node 22.22.1
Reproduction
Setup
A session entry already exists in the target agent's sessions.json with a stale model cached (this happens naturally after 24h of operation, especially after a fallback cascade incident).
Example stale entry in ~/.openclaw/agents/systems_engineer/sessions/sessions.json:
{
"agent:systems_engineer:...": {
"model": "glm-5.1",
"modelProvider": "zai",
"updatedAt": 1775500000000
}
}
Trigger
Spawn response (the lie)
{
"sessionId": "...",
"modelApplied": true
}
Actual behavior (the truth)
Run subagents list ~30 seconds later. The completed entry shows:
model: glm-5.1 ← NOT the requested gpt-5.4
provider: zai
The subagent ran for ~3 minutes on the wrong (weaker) model, with no warning to the orchestrator.
Expected behavior
Either:
- (A)
sessions_spawn with an explicit model argument should always create a fresh session with that model, never resuming a stale one. Or:
- (B) If session-resume is intentional for context-continuity reasons, then:
- The spawn response must include
actualModel: "<provider>/<model>" reflecting the resumed session's effective model
modelApplied must be false if actualModel !== requestedModel
- There should be a
forceFreshSession: true parameter callers can pass to opt out of resume
Actual behavior
- Stale session is silently resumed
modelApplied: true is returned regardless
- The orchestrator has no programmatic way to detect the mismatch — it has to manually re-query
subagents list after every spawn and compare
Impact
This bug compounded a 24-hour fallback cascade incident on 2026-04-06/07. The orchestrator spawned a Systems Engineer recon subagent with explicit model: openai-codex/gpt-5.4, received modelApplied: true, and only discovered post-completion (via subagents list) that the recon had actually run on zai/glm-5.1 — degrading the analysis quality silently.
We had to introduce a mandatory hard rule: every subagent spawn must be verified post-completion via subagents list before its output can be trusted. This is a workaround, not a fix.
Open questions
- Is session-resume on
sessions_spawn intentional? If yes, please document when it triggers (matching key? matching agentId? both?).
- What is the contract of
modelApplied? Is it "the requested model was applied" or "we applied some model"? The current behavior makes it useless as a correctness signal.
- Is there an existing way to force a fresh session on spawn? We could not find one in the CLI / RPC docs.
Suggested fix
- Add
actualModel field to sessions_spawn response (always populated)
- Make
modelApplied reflect effective application, not intended
- Add
forceFreshSession: boolean parameter to sessions_spawn (default behavior TBD by maintainers)
- Document the resume-vs-fresh decision logic clearly
Workaround we are using
- Mandatory
subagents list verification after every spawn
- A 5-minute cron that scans
sessions.json files and clears stale authProfileOverride / providerOverride / modelOverride from auto-source entries older than 10 min (reduces — but does not eliminate — the chance of resuming a sticky-stale session)
Related
- Sister issue: pi-agent-core lifecycle race (
Agent listener invoked outside active run) — filed separately.
- Full incident report available:
~/.openclaw/workspace/output/post-restart-fallback-cascade-incident-report.md
Upstream Bug 2 —
sessions_spawnreturnsmodelApplied: truewhile actually running a stale resumed modelRepo: github.com/openclaw/openclaw
Suggested labels:
bug,gateway,sessions,correctnessOpenClaw version: 2026.4.5
Severity: High — silent model substitution with no visible signal to the orchestrator
Title
sessions_spawnwith explicitmodelargument silently resumes a stale session and runs on the cached model, but the spawn response still reportsmodelApplied: trueSummary
When spawning a subagent with an explicit
modelargument, the gateway appears to resume an existing session entry for that agent (matching byagentId) instead of creating a fresh session. The resumed session can have a stale model cached in its persisted state — meaning the subagent runs on the wrong model while the spawn response cheerfully reportsmodelApplied: true.Two distinct problems:
modelargument is not honored when a stale session entry exists.modelApplied: trueis set based on whether the gateway intended to apply a model, not on whether the actual inference used the requested one.Environment
openclaw@2026.4.5Reproduction
Setup
A session entry already exists in the target agent's
sessions.jsonwith a stale model cached (this happens naturally after 24h of operation, especially after a fallback cascade incident).Example stale entry in
~/.openclaw/agents/systems_engineer/sessions/sessions.json:{ "agent:systems_engineer:...": { "model": "glm-5.1", "modelProvider": "zai", "updatedAt": 1775500000000 } }Trigger
Spawn response (the lie)
{ "sessionId": "...", "modelApplied": true }Actual behavior (the truth)
Run
subagents list~30 seconds later. The completed entry shows:The subagent ran for ~3 minutes on the wrong (weaker) model, with no warning to the orchestrator.
Expected behavior
Either:
sessions_spawnwith an explicitmodelargument should always create a fresh session with that model, never resuming a stale one. Or:actualModel: "<provider>/<model>"reflecting the resumed session's effective modelmodelAppliedmust befalseifactualModel !== requestedModelforceFreshSession: trueparameter callers can pass to opt out of resumeActual behavior
modelApplied: trueis returned regardlesssubagents listafter every spawn and compareImpact
This bug compounded a 24-hour fallback cascade incident on 2026-04-06/07. The orchestrator spawned a Systems Engineer recon subagent with explicit
model: openai-codex/gpt-5.4, receivedmodelApplied: true, and only discovered post-completion (viasubagents list) that the recon had actually run onzai/glm-5.1— degrading the analysis quality silently.We had to introduce a mandatory hard rule: every subagent spawn must be verified post-completion via
subagents listbefore its output can be trusted. This is a workaround, not a fix.Open questions
sessions_spawnintentional? If yes, please document when it triggers (matching key? matching agentId? both?).modelApplied? Is it "the requested model was applied" or "we applied some model"? The current behavior makes it useless as a correctness signal.Suggested fix
actualModelfield tosessions_spawnresponse (always populated)modelAppliedreflect effective application, not intendedforceFreshSession: booleanparameter tosessions_spawn(default behavior TBD by maintainers)Workaround we are using
subagents listverification after every spawnsessions.jsonfiles and clears staleauthProfileOverride/providerOverride/modelOverridefromauto-source entries older than 10 min (reduces — but does not eliminate — the chance of resuming a sticky-stale session)Related
Agent listener invoked outside active run) — filed separately.~/.openclaw/workspace/output/post-restart-fallback-cascade-incident-report.md