Skip to content

openai-codex fallback sends 'gpt-5-4' instead of 'gpt-5.4' to Codex backend, returning HTTP 404 #17171

@sean808080

Description

@sean808080

Summary

When the Hermes fallback chain activates openai-codex with model gpt-5.4 (the documented Codex chat model), the request reaches the ChatGPT Codex backend with model name gpt-5-4 (dots replaced with hyphens) and gets HTTP 404. The Codex /responses endpoint accepts only gpt-5.4 (with the dot).

The conversion is not in hermes_cli/model_normalize.pynormalize_model_for_provider("gpt-5.4", "openai-codex") returns "gpt-5.4" correctly. The dot→hyphen rewrite is happening downstream of normalization, somewhere in the codex_responses request-build / fallback-activation path.

Environment

  • Hermes Agent: latest (post hermes update 2026-04-28)
  • macOS 15.x arm64
  • Provider chain (config.yaml):
    model: claude-haiku-4-5-20251001
    fallback_providers:
      - provider: anthropic
        model: claude-sonnet-4-6
      - provider: openai-codex
        model: gpt-5.4
      - provider: openrouter
        model: meta-llama/llama-3.3-70b-instruct:free
  • Codex auth: working (token freshly refreshed via Codex CLI, pool entry last_status: ok)
  • Codex backend: https://chatgpt.com/backend-api/codex (default)

Reproduction

  1. Configure openai-codex with model gpt-5.4 anywhere in the chain.
  2. Trigger fallback (e.g. by sending a request when the primary is rate-limited, or by setting primary to gpt-5.4 directly).
  3. Observe gateway log:
🔄 Primary model failed — switching to fallback: gpt-5.4 via openai-codex
⚠️  API call failed (attempt 1/3): NotFoundError [HTTP 404]
   🔌 Provider: openai-codex  Model: gpt-5.4
   🌐 Endpoint: https://chatgpt.com/backend-api/codex
   📝 Error: HTTP 404: model: gpt-5-4

Note the discrepancy: log line Model: gpt-5.4 (the configured value), but error message from the backend says gpt-5-4 — the wire-level model name was rewritten.

Confirmation that Codex backend itself works

Same machine, same OAuth token, same minute — direct curl to the Codex backend with gpt-5.4 returns 200:

TOKEN=$(python3 -c "import json,os; d=json.load(open(os.path.expanduser('~/.hermes/auth.json'))); print(d['credential_pool']['openai-codex'][0]['access_token'])")

curl -sN -X POST https://chatgpt.com/backend-api/codex/responses \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -H "OpenAI-Beta: responses=experimental" \
  -d '{"model":"gpt-5.4","input":[{"role":"user","content":"Reply: WORKING"}],"instructions":"helpful","stream":true,"store":false}'
# → SSE stream, response.created with model: "gpt-5.4", deltas "WORK" + "ING"

Same payload with gpt-5 or gpt-5-codex:

{"detail":"The 'gpt-5-codex' model is not supported when using Codex with a ChatGPT account."}

So the backend strictly accepts gpt-5.4 (with the dot) and rejects the dash form.

What I've ruled out

  • model_normalize.py: I verified normalize_model_for_provider("gpt-5.4", "openai-codex") returns "gpt-5.4". openai-codex is in _STRIP_VENDOR_ONLY_PROVIDERS (dots preserved), not _DOT_TO_HYPHEN_PROVIDERS.
  • agent/anthropic_adapter.py: contains model.replace(".", "-") calls but only on the Anthropic path.
  • agent/model_metadata.py:1057: contains return model.replace(".", "-") but it's in a comparison helper, not the wire path.

Suspected location

Somewhere in the codex_responses fallback path:

  • run_agent.py _try_activate_fallback → constructs the responses request body
  • agent/auxiliary_client.py CodexAuxiliaryClient / resolve_provider_client Codex branch
  • Or a model-comparison helper that normalizes both sides for matching but accidentally returns the normalized form to the wire layer

I don't have a definitive line number. Adding print statements just before the client.responses.stream() call would localize it quickly.

Related issues

These are not duplicates but share the same dot→hyphen rewrite pattern affecting different providers / paths:

If a single root cause lurks, fixing one might fix all four.

Impact

Anyone configuring openai-codex with gpt-5.4 (or any GPT-5.x with a dot) as a primary or fallback gets a 100% failure rate on that hop. Especially painful right now because Anthropic Sonnet/Opus on subscription OAuth is currently being gated by Anthropic (#17169), making openai-codex the natural backstop — which then 404s.

Workaround

None on the user side. The model name gpt-5-4 doesn't exist in Codex; gpt-5.4 is the canonical value. Direct API calls work; only Hermes-routed ones fail.

What might fix it

  • Find the offending .replace(".", "-") and gate it behind a provider check.
  • Or replace it with the centralized normalize_model_for_provider so the "preserve dots for _STRIP_VENDOR_ONLY_PROVIDERS" rule applies.

Happy to provide gateway logs, full request dumps, or run a focused trace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/gatewayGateway runner, session dispatch, deliveryprovider/openaiOpenAI / Codex Responses APItype/bugSomething isn't working

    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