Bug Description
Cron jobs with sessionTarget: "isolated" and a payload.model override enter an infinite LiveSessionModelSwitchError loop when the agent's default model (in openclaw.json agents list) differs from the cron payload model.
Steps to Reproduce
- Set agent default model to
zai/glm-5-turbo in openclaw.json:
"agents": { "list": [{ "id": "main", "model": { "primary": "zai/glm-5-turbo" } }] }
- Create a cron job with a different
payload.model:
{
"name": "test",
"agentId": "main",
"sessionTarget": "isolated",
"payload": { "kind": "agentTurn", "message": "hello", "model": "minimax-portal/MiniMax-M2.7" }
}
- Run the cron job →
LiveSessionModelSwitchError: Live session model switch requested: zai/glm-5-turbo
Root Cause
Field name mismatch between two code paths:
Cron dispatch (src/cron/isolated-agent/run-config.ts ~line 4861) writes:
cronSession.sessionEntry.modelProvider = provider; // "minimax-portal"
cronSession.sessionEntry.model = model; // "MiniMax-M2.7"
Embedded run (resolveLiveSessionModelSelection in auth-profiles.ts) reads:
const provider = entry?.providerOverride?.trim() || defaultModelRef.provider;
const model = entry?.modelOverride?.trim() || defaultModelRef.model;
Since providerOverride / modelOverride are never written by cron dispatch, the function always falls back to resolveDefaultModelForAgent() which returns the agent config model (glm-5-turbo). This doesn't match the cron payload model (M2.7), triggering LiveSessionModelSwitchError.
The outer catch handles the error by switching to glm-5-turbo, but then model fallback kicks in (M2.7 fails → glm-5 fails → kimi), and each fallback attempt re-triggers the live switch check, creating a loop until retry limit.
Environment
- OpenClaw version: 2026.3.28 (f9b1079)
- OS: macOS (arm64)
- Node: v24.13.1
Suggested Fix
Either:
- In cron dispatch: Also write the override fields:
cronSession.sessionEntry.modelProvider = provider;
cronSession.sessionEntry.model = model;
cronSession.sessionEntry.providerOverride = provider; // add
cronSession.sessionEntry.modelOverride = model; // add
- In
resolveLiveSessionModelSelection: Also check the non-override fields:
const provider = entry?.providerOverride?.trim() || entry?.modelProvider?.trim() || defaultModelRef.provider;
const model = entry?.modelOverride?.trim() || entry?.model?.trim() || defaultModelRef.model;
Option 2 is safer as it's backward compatible with any code path that writes either field name.
Bug Description
Cron jobs with
sessionTarget: "isolated"and apayload.modeloverride enter an infiniteLiveSessionModelSwitchErrorloop when the agent's default model (inopenclaw.jsonagents list) differs from the cron payload model.Steps to Reproduce
zai/glm-5-turboinopenclaw.json:payload.model:{ "name": "test", "agentId": "main", "sessionTarget": "isolated", "payload": { "kind": "agentTurn", "message": "hello", "model": "minimax-portal/MiniMax-M2.7" } }LiveSessionModelSwitchError: Live session model switch requested: zai/glm-5-turboRoot Cause
Field name mismatch between two code paths:
Cron dispatch (
src/cron/isolated-agent/run-config.ts~line 4861) writes:Embedded run (
resolveLiveSessionModelSelectioninauth-profiles.ts) reads:Since
providerOverride/modelOverrideare never written by cron dispatch, the function always falls back toresolveDefaultModelForAgent()which returns the agent config model (glm-5-turbo). This doesn't match the cron payload model (M2.7), triggeringLiveSessionModelSwitchError.The outer catch handles the error by switching to
glm-5-turbo, but then model fallback kicks in (M2.7 fails → glm-5 fails → kimi), and each fallback attempt re-triggers the live switch check, creating a loop until retry limit.Environment
Suggested Fix
Either:
resolveLiveSessionModelSelection: Also check the non-override fields:Option 2 is safer as it's backward compatible with any code path that writes either field name.