Skip to content

sessions_spawn returns modelApplied:true while actually running a stale resumed model #63221

@jdroblee-afk

Description

@jdroblee-afk

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:

  1. Routing bug: Explicit model argument is not honored when a stale session entry exists.
  2. 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

// MCP / RPC call
sessions_spawn({
  "agentId": "systems_engineer",
  "model": "openai-codex/gpt-5.4",
  "task": "..."
})

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

  1. Is session-resume on sessions_spawn intentional? If yes, please document when it triggers (matching key? matching agentId? both?).
  2. 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.
  3. 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

  1. Mandatory subagents list verification after every spawn
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions