Custom provider HTTP 500 errors are mislabeled as OpenAI high demand
What version of Codex CLI is running?
codex-cli 0.144.3
Platform
macOS arm64
What issue are you seeing?
When a custom OpenAI-compatible Responses provider returns HTTP 500, Codex discards the provider error details and displays:
We are currently experiencing high demand, which may cause temporary errors.
That message attributes an arbitrary custom-provider failure to service demand. A custom provider can use HTTP 500 for many unrelated conditions, so the message is misleading and hides the diagnostic information needed to fix the provider or request.
Minimal reproduction
- Configure a custom provider with
wire_api = "responses"and an HTTP base URL. - Have the fixture endpoint return:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{"error":{"code":"fixture_failure","message":"fixture-specific failure"}}
- Send any Codex prompt through that provider.
- Observe that Codex reports generic high demand rather than the HTTP status or fixture error.
Expected behavior
For custom providers, Codex should preserve a bounded provider error message, for example:
Custom provider returned HTTP 500: fixture-specific failure
The OpenAI-specific high-demand wording should be reserved for an explicit overload/capacity error code, not every HTTP 500.
Source-level cause
In codex-rs/codex-api/src/api_bridge.rs, TransportError::Http maps every StatusCode::INTERNAL_SERVER_ERROR directly to CodexErr::InternalServerError. In codex-rs/protocol/src/error.rs, that variant has the fixed high-demand display text. The HTTP body is therefore discarded for this status.
A safer mapping would retain the bounded response body for custom providers, or use the generic UnexpectedStatus representation unless an explicit overload code is present.
Additional information
This is the general form of the behavior previously reported for another custom backend in #2445, but it remains reproducible in CLI 0.144.3. This report intentionally uses only a synthetic fixture and contains no private provider details.
2 Comments
I've implemented and verified a fix for this, available here if the team wants to invite a PR (creating one directly is blocked for external accounts):
Branch: https://github.com/tingxiao88/codex/tree/fix-custom-provider-500-mislabeled
Diff: https://github.com/openai/codex/compare/main...tingxiao88:codex:fix-custom-provider-500-mislabeled
Approach:
CodexErr::InternalServerErrornow carriesmessage: Option<String>. The 500 branch inapi_bridge.rsextracts the JSONerror.messagefrom the body (mirroring how the neighboring 503/400/429 branches parse theirs), so the CLI shows:Explicit overload codes (
server_is_overloaded/slow_down) and bodyless/non-JSON 500s keep the existing high-demand message, and the display is bounded byERROR_MESSAGE_UI_MAX_BYTES.I deliberately did not reroute 500s to
UnexpectedStatus: that variant maps toCodexErrorInfo::Other, and the guardian review retry loop retriesInternalServerErrorbut notOther— a reroute would silently change guardian retry behavior. Keeping the variant means retryability, guardian retry, compaction model fallback, and analytics classification are all unchanged; only the message improves.Verified with 4 new unit tests in
api_bridge_tests.rs(all 15map_api_errortests pass, clippy clean) and end-to-end against a local fixture returning500 {"error":{"code":"fixture_failure","message":"fixture-specific failure"}}through awire_api = "responses"custom provider — before: the high-demand message; after: the provider's actual error.Happy to submit this as a PR if invited.
Same issue, with almost any OpenRouter model.