openclaw - 💡(How to fix) Fix Docs describe agentRuntime fields (provider-scoped, model-scoped) that 2026.5.7 schema rejects and source code does not read

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…

The agent-runtimes and config-agents documentation pages describe four locations for setting agentRuntime.id (provider-scoped, model-scoped at agent-defaults, model-scoped at agent-list, and a fallback "auto" mode), and explicitly state that the agent-level form (agents.list[].agentRuntime, agents.defaults.agentRuntime) is "legacy and ignored." In 2026.5.7, the opposite is true at every layer:

  1. The schema rejects all four documented locations with additionalProperties: false.
  2. The runtime-resolver source code only reads from the two locations the docs label as ignored.
  3. openclaw doctor --fix correctly preserves agent-level pins (because nothing else works), directly contradicting the docs claim that doctor "removes old whole-agent runtime pins."
  4. Following the docs literally produces an immediate oc config validate failure.

The docs read as a target architecture spec; the implementation in 2026.5.7 has not landed any of it.

Root Cause

  1. The schema rejects all four documented locations with additionalProperties: false.
  2. The runtime-resolver source code only reads from the two locations the docs label as ignored.
  3. openclaw doctor --fix correctly preserves agent-level pins (because nothing else works), directly contradicting the docs claim that doctor "removes old whole-agent runtime pins."
  4. Following the docs literally produces an immediate oc config validate failure.

Code Example

{
     "models": {
       "providers": {
         "anthropic": {
           "baseUrl": "https://api.anthropic.com",
           "api": "anthropic-messages",
           "models": [
             { "id": "claude-opus-4-7", "name": "Opus 4.7 (Max)",
               "contextWindow": 1000000, "contextTokens": 800000 }
           ]
         }
       }
     },
     "agents": {
       "list": [{
         "id": "main", "name": "Jennifer",
         "model": "anthropic/claude-opus-4-7",
         "agentRuntime": { "id": "claude-cli" }
       }]
     }
   }

---

"models": {
     "providers": {
       "anthropic": {
         "agentRuntime": { "id": "claude-cli" },
         "baseUrl": "https://api.anthropic.com",
         ...
       }
     }
   }

---

"agents": {
     "defaults": {
       "models": {
         "anthropic/claude-opus-4-7": { "agentRuntime": { "id": "claude-cli" } }
       }
     }
   }

---

export function resolveAgentRuntimePolicy(
  container: AgentRuntimePolicyContainer | undefined,
): AgentRuntimePolicyConfig | undefined {
  const preferred = container?.agentRuntime;
  if (hasAgentRuntimePolicy(preferred)) {
    return preferred;
  }
  return undefined;
}

---

function resolveConfiguredRuntime(params) {
  if (params.agentId) {
    const agentEntry = params.cfg?.agents?.list?.find(...);
    const agentRuntime = resolveAgentRuntimePolicy(agentEntry)?.id?.trim();
    if (agentRuntime) return normalizeProviderId(agentRuntime);
  }
  const defaults = resolveAgentRuntimePolicy(params.cfg?.agents?.defaults)?.id?.trim();
  if (defaults) return normalizeProviderId(defaults);
}

---

sha256(/app/dist/model-runtime-aliases-CN0ccyIq.js):

customized container:  05d1822d488ca8b040f3e8e8d2b40d06804c59ca2fe19b7204fa54e761e11272
pristine upstream:     05d1822d488ca8b040f3e8e8d2b40d06804c59ca2fe19b7204fa54e761e11272
RAW_BUFFERClick to expand / collapse

Summary

The agent-runtimes and config-agents documentation pages describe four locations for setting agentRuntime.id (provider-scoped, model-scoped at agent-defaults, model-scoped at agent-list, and a fallback "auto" mode), and explicitly state that the agent-level form (agents.list[].agentRuntime, agents.defaults.agentRuntime) is "legacy and ignored." In 2026.5.7, the opposite is true at every layer:

  1. The schema rejects all four documented locations with additionalProperties: false.
  2. The runtime-resolver source code only reads from the two locations the docs label as ignored.
  3. openclaw doctor --fix correctly preserves agent-level pins (because nothing else works), directly contradicting the docs claim that doctor "removes old whole-agent runtime pins."
  4. Following the docs literally produces an immediate oc config validate failure.

The docs read as a target architecture spec; the implementation in 2026.5.7 has not landed any of it.

Reproduction

  1. Start with a clean ~/.openclaw/openclaw.json containing an Anthropic Max + claude-cli setup (the canonical case the docs example covers):

    {
      "models": {
        "providers": {
          "anthropic": {
            "baseUrl": "https://api.anthropic.com",
            "api": "anthropic-messages",
            "models": [
              { "id": "claude-opus-4-7", "name": "Opus 4.7 (Max)",
                "contextWindow": 1000000, "contextTokens": 800000 }
            ]
          }
        }
      },
      "agents": {
        "list": [{
          "id": "main", "name": "Jennifer",
          "model": "anthropic/claude-opus-4-7",
          "agentRuntime": { "id": "claude-cli" }
        }]
      }
    }

    oc config validate passes. Inference works. /status routes through claude-cli runtime. Good.

  2. Per the docs at https://docs.openclaw.ai/concepts/agent-runtimes ("whole-agent runtime keys are legacy and ignored"), migrate to the documented provider-scoped form: remove agentRuntime from the agent entry, add it to the provider:

    "models": {
      "providers": {
        "anthropic": {
          "agentRuntime": { "id": "claude-cli" },
          "baseUrl": "https://api.anthropic.com",
          ...
        }
      }
    }
  3. Run oc config validate.

    Observed: models.providers.anthropic: Unrecognized key: "agentRuntime".

    Expected per docs: validation passes; the runtime selects claude-cli for any anthropic/<model> ref via "provider-scoped runtime policy."

  4. Try the model-scoped form from the example at https://docs.openclaw.ai/gateway/config-agents#runtime-policy:

    "agents": {
      "defaults": {
        "models": {
          "anthropic/claude-opus-4-7": { "agentRuntime": { "id": "claude-cli" } }
        }
      }
    }

    Observed: validation fails the same way; agents.defaults.models["anthropic/claude-opus-4-7"] schema only allows alias, params, streaming with additionalProperties: false.

  5. Run oc doctor --fix against the working agent-level form (step 1).

    Observed: doctor leaves agents.list[<id>].agentRuntime in place. No "removal of old whole-agent runtime pins" as the docs describe.

    Expected per docs: doctor "removes old whole-agent runtime pins and rewrites legacy runtime model refs to canonical provider/model refs plus model-scoped runtime policy where needed."

Source reference

src/agents/agent-runtime-policy.ts at tag v2026.5.7:

export function resolveAgentRuntimePolicy(
  container: AgentRuntimePolicyContainer | undefined,
): AgentRuntimePolicyConfig | undefined {
  const preferred = container?.agentRuntime;
  if (hasAgentRuntimePolicy(preferred)) {
    return preferred;
  }
  return undefined;
}

src/agents/model-runtime-aliases.ts at tag v2026.5.7 (shows the only callers):

function resolveConfiguredRuntime(params) {
  if (params.agentId) {
    const agentEntry = params.cfg?.agents?.list?.find(...);
    const agentRuntime = resolveAgentRuntimePolicy(agentEntry)?.id?.trim();
    if (agentRuntime) return normalizeProviderId(agentRuntime);
  }
  const defaults = resolveAgentRuntimePolicy(params.cfg?.agents?.defaults)?.id?.trim();
  if (defaults) return normalizeProviderId(defaults);
}

The resolver accepts a generic container with an optional agentRuntime field, but every call site passes cfg.agents.list[<entry>] or cfg.agents.defaults. No call site anywhere in /app/dist passes a models.providers.<X> entry, a per-model entry from models.providers.<X>.models[], an agents.defaults.models["X"] entry, or an agents.list[].models["X"] entry.

Schema reference

Schema fields with agentRuntime declared (from oc config schema against pristine ghcr.io/openclaw/openclaw:2026.5.7):

  • agents.defaults.agentRuntime
  • agents.list[].agentRuntime

Schema fields the docs say should accept agentRuntime but reject it (additionalProperties: false):

Docs pathAllowed property names in schema
models.providers.<X>api, apiKey, auth, authHeader, baseUrl, contextTokens, contextWindow, headers, injectNumCtxForOpenAICompat, maxTokens, models, params, request, timeoutSeconds
models.providers.<X>.models[]api, baseUrl, compat, contextTokens, contextWindow, cost, headers, id, input, maxTokens, metadataSource, name, params, reasoning
agents.defaults.models["X"]alias, params, streaming
agents.list[].models["X"]path not declared in schema; agents.list[] items do not define a models map

Confirmed identical on the main branch as of this filing. src/config/types.models.ts on main contains zero agentRuntime references.

Verification (not a tainted install)

To rule out local taint, I compared a customized image (apt build tools + brew + claude-cli npm install on top of the official base) against pristine ghcr.io/openclaw/openclaw:2026.5.7:

sha256(/app/dist/model-runtime-aliases-CN0ccyIq.js):

customized container:  05d1822d488ca8b040f3e8e8d2b40d06804c59ca2fe19b7204fa54e761e11272
pristine upstream:     05d1822d488ca8b040f3e8e8d2b40d06804c59ca2fe19b7204fa54e761e11272

oc config schema exported from both images is byte-identical for the runtime-related sections. The discrepancy lives in the published image, not in any local build artifact.

Request

Pick one of these (any one closes the gap):

  • Update the docs to reflect 2026.5.7 reality. The agent-level form is the supported form in 2026.5.x. Mark the four model-scoped/provider-scoped locations as "planned" or version-gate them to a future release. Remove the "ignored" claim about agent-level keys.
  • Ship the implementation that the docs describe. Add the four locations to the schema, route them through resolveAgentRuntimePolicy (the resolver function already takes a generic container, so wiring is mostly call-site work), and have doctor --fix migrate from agent-level to model-scoped/provider-scoped as the docs claim.
  • If a partial migration is intended, version-gate it. Add a transitional note that says which form works in which version, with a clear "use agent-level today, model-scoped from <future-version>" instruction.

Use case

Operator running OpenClaw 2026.5.7 in Docker, multi-agent setup with mixed runtime backends (some agents on claude-cli for Anthropic Max OAuth, others on the embedded pi runtime for OpenRouter models). Tried to follow the docs to migrate from per-agent runtime overrides to provider-scoped overrides for cleaner config (specifically, to avoid duplicating agentRuntime: { id: "claude-cli" } on each agent that uses anthropic/<model>).

The result was an immediate oc config validate failure with no in-doc guidance about the schema rejection. Rolling back to the agent-level form (the form the docs say is "ignored") was the only way to get a passing config. Discovering this required exporting the schema, decompiling the runtime resolver, and cross-checking the GitHub source at the release tag, which is work that the docs implied was unnecessary.

This wasted several hours of operator time on what the docs framed as a clean migration step.

Related issues

  • #79015. Display bug surface from this same architectural mismatch (status renders "Fallback: claude-cli/X (selected model unavailable)" when an anthropic/X model routes through the agent-level claude-cli override). The display bug only exists because operators are forced to use the agent-level form against the docs guidance.
  • #76267. claude-cli/<model> model refs rejected in isolated cron sessions since v2026.4.29. Adjacent surface (model-ref normalization) where the docs/schema expectations diverge from runtime behavior.
  • #74310. normalizeProviderId breaks provider-namespaced models. Same family of provider/runtime naming gaps.
  • #78953. Docs/runtime disagreement on memorySearch embedding cache default. Same shape of bug (docs describe a feature the runtime does not implement as written).

OpenClaw version

2026.5.7 (Docker, both pristine ghcr.io/openclaw/openclaw:2026.5.7 and a customized derivative; behavior identical at the byte level). Source verified at git tag v2026.5.7. main branch confirmed to have no schema additions since the tag.

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