Skip to content

Codex harness migration: agentRuntime.fallback="none" doesn't keep non-codex fallbacks off codex; canonical openai/* ref doesn't broker openai-codex OAuth profile #75739

@mogglemoss

Description

@mogglemoss

Summary

When migrating to the canonical codex-harness setup documented at https://docs.openclaw.ai/plugins/codex-harness, two related runtime-routing bugs surface together on 2026.4.29:

  1. Primary openai/gpt-5.5 + agentRuntime: { id: "codex" } does not broker an existing openai-codex:<email> OAuth profile. The request hits https://api.openai.com/v1/responses directly with no Authorization header → 401 Unauthorized: Missing bearer or basic authentication in header.
  2. agentRuntime.fallback: "none" does not keep non-codex fallbacks off the codex runtime. When the primary fails, a fallback like moonshot/kimi-k2.5 is still routed through the codex harness (harnessId: "codex", provider: "moonshot") and dies with failed to load configuration: Model provider 'moonshot' not found. With fallback: "none" set, I would expect non-codex fallbacks to use their normal provider runtimes (PI runner, etc.), not be forced through codex.

Net effect: an agent following the official codex-harness migration goes silent across its entire fallback chain.

Repro

Working baseline (legacy config, fully operational on the same box):

{
  "auth": { "profiles": {
    "openai-codex:<email>": { "provider": "openai-codex", "mode": "oauth", "email": "<email>" }
  }},
  "agents": { "defaults": {
    "model": {
      "primary": "openai-codex/gpt-5.5",
      "fallbacks": ["moonshot/kimi-k2.5", "anthropic/claude-sonnet-4-6"]
    },
    "models": { "openai-codex/gpt-5.4": {}, "openai-codex/gpt-5.5": {} }
  }}
}

Migrate to the docs' canonical pattern (https://docs.openclaw.ai/plugins/codex-harness):

{
  "auth": { /* unchanged — kept openai-codex:<email> OAuth profile */ },
  "plugins": { "entries": { "codex": { "enabled": true } } },
  "agents": { "defaults": {
    "model": {
      "primary": "openai/gpt-5.5",
      "fallbacks": ["moonshot/kimi-k2.5", "anthropic/claude-sonnet-4-6"]
    },
    "agentRuntime": { "id": "codex", "fallback": "none" },
    "models": {
      "openai/gpt-5.4": {}, "openai/gpt-5.5": {},
      "openai-codex/gpt-5.4": {}, "openai-codex/gpt-5.5": {}
    }
  }}
}

openclaw gateway restart. Send any DM to a configured channel (Discord/Telegram).

Observed

Gateway logs (sanitized; runId and request hashes preserved):

gateway: agent model: openai/gpt-5.5
gateway: http server listening (10 plugins: acpx, browser, codex, device-pair, discord,
         file-transfer, memory-core, phone-control, talk-voice, telegram; 8.8s)
plugins: file-transfer staging bundled runtime deps (51 specs): ... @openai/codex@0.125.0 ...

agent/embedded {"event":"embedded_run_failover_decision","stage":"prompt",
  "decision":"fallback_model","failoverReason":"auth","profileFailureReason":"auth",
  "provider":"openai","model":"gpt-5.5","status":401,
  "rawErrorPreview":"unexpected status 401 Unauthorized: Missing bearer or basic
   authentication in header, url: https://api.openai.com/v1/responses, ..."}

diagnostic: lane task error: lane=main durationMs=26103
  error="FailoverError: unexpected status 401 Unauthorized: Missing bearer or basic
  authentication in header, url: https://api.openai.com/v1/responses"

model-fallback/decision {"decision":"candidate_failed",
  "candidateProvider":"openai","candidateModel":"gpt-5.5","reason":"auth",
  "fallbackStepFromModel":"openai/gpt-5.5",
  "fallbackStepToModel":"moonshot/kimi-k2.5", ...}

agents/harness {"harnessId":"codex","provider":"moonshot","modelId":"kimi-k2.5",
  "error":"failed to load configuration: Model provider `moonshot` not found"}
  Codex agent harness failed; not falling back to embedded PI backend

diagnostic: lane task error: lane=main durationMs=8480
  error="CodexAppServerRpcError: failed to load configuration:
  Model provider `moonshot` not found"

model-fallback/decision {"decision":"candidate_failed",
  "candidateProvider":"moonshot","candidateModel":"kimi-k2.5",
  "fallbackStepToModel":"anthropic/claude-sonnet-4-6", ...}

Expected

  • (1) With agentRuntime: { id: "codex" } and the model ref openai/gpt-5.5, the codex harness should bind the existing openai-codex:<email> OAuth profile by virtue of agent-binding (per https://docs.openclaw.ai/concepts/oauth: "An explicit OpenClaw openai-codex auth profile bound to the agent.") and use Codex's OAuth flow rather than hitting api.openai.com unauthenticated. If a separate config block is required to bind the profile to the codex plugin, the migration docs should say so explicitly — currently they don't mention any auth wiring beyond keeping the existing profile.
  • (2) With agentRuntime.fallback: "none", fallback candidates whose providers aren't supported by codex (moonshot, anthropic) should run via their own provider runtimes (the embedded PI backend), not be forced through the codex harness. The current behavior makes the codex harness an all-or-nothing trap for any agent that has cross-provider fallbacks.

Notes

  • openclaw doctor --fix does not auto-migrate legacy openai-codex/* model refs to canonical openai/* refs, despite the migration docs implying it does ("Doctor compatibility migration rewrites legacy primary runtime refs to canonical model refs and records the runtime policy separately." — https://docs.openclaw.ai/plugins/codex-harness). Worth a separate look or a doc clarification.
  • Reverting model.primary back to openai-codex/gpt-5.5 (and removing the agentRuntime and plugins.entries.codex blocks) restores the working OAuth-via-PI-runner path immediately.

Environment

  • openclaw 2026.4.29 (Homebrew)
  • Node.js (Homebrew)
  • macOS Darwin 25.2.0 (Apple Silicon)
  • Channels: Discord + Telegram, both configured and connected pre-migration
  • Auth profiles: openai-codex:<email> (oauth), anthropic:default (token), moonshot:default (api_key), google:default (api_key)

Possibly related

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    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