openclaw - 💡(How to fix) Fix doctor: warn when string-form per-agent model silently overrides agents.defaults.model.fallbacks [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When a per-agent model is set as a STRING (e.g., "model": "openai-codex/gpt-5.5"), openclaw's resolveAgentModelFallbacksOverride() returns [], which clobbers any inherited agents.defaults.model.fallbacks chain at runtime. The agent ends up with zero fallbacks despite the defaults block clearly specifying a chain.

This is silent — no log warning, no doctor diagnostic, no startup notice. The user only finds out when the primary fails: the runtime surfaces the auth error directly to the chat client (e.g., Telegram), instead of cascading to the configured fallback model.

Error Message

This is silent — no log warning, no doctor diagnostic, no startup notice. The user only finds out when the primary fails: the runtime surfaces the auth error directly to the chat client (e.g., Telegram), instead of cascading to the configured fallback model. When codex auth fails (e.g., refresh_token_reused), main has no fallbacks at runtime — even though the user reasonably expects the defaults chain to apply. The user-facing result is the bare openclaw auth error message rendered as the agent's reply. FortiumClaw's 4 agent bots had their fallback chain silently disabled for ~36h while the codex OAuth refresh token was invalidated (refresh_token_reused error from the OpenAI token endpoint). All four agents were configured with string-form model overrides that looked correct against the defaults block, but at runtime they had no fallbacks. End users (in Telegram) saw the raw openclaw auth error string in place of agent replies, instead of a seamless Anthropic fallback. There was no surface in openclaw doctor, the gateway logs at INFO, or the agent startup output that would have caught this — the only signal was the eventual user-facing failure.

Root Cause

When a per-agent model is set as a STRING (e.g., "model": "openai-codex/gpt-5.5"), openclaw's resolveAgentModelFallbacksOverride() returns [], which clobbers any inherited agents.defaults.model.fallbacks chain at runtime. The agent ends up with zero fallbacks despite the defaults block clearly specifying a chain.

This is silent — no log warning, no doctor diagnostic, no startup notice. The user only finds out when the primary fails: the runtime surfaces the auth error directly to the chat client (e.g., Telegram), instead of cascading to the configured fallback model.

Fix Action

Fixed

Code Example

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "openai-codex/gpt-5.5",
        "fallbacks": ["openai-codex/gpt-5.5", "anthropic/claude-opus-4-6"]
      }
    },
    "list": [
      { "id": "main", "model": "openai-codex/gpt-5.5" }
    ]
  }
}

---

{
  "id": "main",
  "model": {
    "primary": "openai-codex/gpt-5.5",
    "fallbacks": ["anthropic/claude-opus-4-6"]
  }
}
RAW_BUFFERClick to expand / collapse

Summary

When a per-agent model is set as a STRING (e.g., "model": "openai-codex/gpt-5.5"), openclaw's resolveAgentModelFallbacksOverride() returns [], which clobbers any inherited agents.defaults.model.fallbacks chain at runtime. The agent ends up with zero fallbacks despite the defaults block clearly specifying a chain.

This is silent — no log warning, no doctor diagnostic, no startup notice. The user only finds out when the primary fails: the runtime surfaces the auth error directly to the chat client (e.g., Telegram), instead of cascading to the configured fallback model.

Concrete reproduction

Footgun config:

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "openai-codex/gpt-5.5",
        "fallbacks": ["openai-codex/gpt-5.5", "anthropic/claude-opus-4-6"]
      }
    },
    "list": [
      { "id": "main", "model": "openai-codex/gpt-5.5" }
    ]
  }
}

When codex auth fails (e.g., refresh_token_reused), main has no fallbacks at runtime — even though the user reasonably expects the defaults chain to apply. The user-facing result is the bare openclaw auth error message rendered as the agent's reply.

The correct config shape (what works):

{
  "id": "main",
  "model": {
    "primary": "openai-codex/gpt-5.5",
    "fallbacks": ["anthropic/claude-opus-4-6"]
  }
}

But this difference is undocumented and easy to miss — the string form looks like a perfectly reasonable shorthand for "use this primary, inherit everything else from defaults".

Runtime evidence

In agent-scope-B6RIBoEj.js:177-184, resolveAgentModelFallbacksOverride() returns [] when the input model is a string. That empty array then replaces (rather than merges with) the inherited agents.defaults.model.fallbacks chain. There is no warning at config-load time, no startup log entry, and no doctor diagnostic that flags the mismatch.

Real-world impact

FortiumClaw's 4 agent bots had their fallback chain silently disabled for ~36h while the codex OAuth refresh token was invalidated (refresh_token_reused error from the OpenAI token endpoint). All four agents were configured with string-form model overrides that looked correct against the defaults block, but at runtime they had no fallbacks. End users (in Telegram) saw the raw openclaw auth error string in place of agent replies, instead of a seamless Anthropic fallback. There was no surface in openclaw doctor, the gateway logs at INFO, or the agent startup output that would have caught this — the only signal was the eventual user-facing failure.

Proposed fix

Add an openclaw doctor diagnostic that detects this exact pattern:

  • Per-agent model is a STRING
  • AND agents.defaults.model.fallbacks is non-empty

When both are true, emit a warning along the lines of:

Agent <id> overrides model with a string; this DISABLES the inherited agents.defaults.model.fallbacks chain. Use the object form {primary, fallbacks} to keep fallbacks active.

Optionally, an openclaw doctor --fix flag could migrate the string form into {primary: <string>, fallbacks: <inherited from defaults>} automatically, leaving a comment in the resulting config indicating the migration source.

Reference

We applied a local config fix in our downstream repo using the migration shape described above — see FortiumPartners/nemoclaw#60 for the exact PR that converted our string-form agent overrides into {primary, fallbacks} objects. That migration is the same shape --fix would want to produce.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix doctor: warn when string-form per-agent model silently overrides agents.defaults.model.fallbacks [1 pull requests]