Codex fails against custom OpenAI-compatible (Responses API) provider with `upstream_error`, while identical curl requests succeed
Summary
With a custom [model_providers.*] pointing at an OpenAI-compatible Responses API endpoint (Pioneer, https://api.pioneer.ai/v1), every Codex request fails:
ERROR: stream disconnected before completion: response.failed event received
The upstream SSE stream Codex receives is:
{"type": "response.failed", "sequence_number": 3,
"response": {"id": "resp_...", "status": "failed", "error": null,
"model": "gpt-5.5", "output": []},
"error": {"message": "Upstream provider error",
"type": "server_error", "code": "upstream_error"}}
The same provider works perfectly from curl and other clients. I captured Codex's exact request body + headers and replayed them with curl — they succeed. So the failure is specific to how the Codex client itself drives the connection, not the provider, the key, or billing.
Environment
codex-cli 0.134.0- macOS 26.2 (arm64), zsh
- Provider: Pioneer (OpenAI-compatible, Responses API),
wire_api = "responses", Bearer auth viaenv_key - Models tried:
gpt-5.5,claude-opus-4-7,claude-sonnet-4-6(all fail identically)
Config
model = "gpt-5.5"
model_provider = "pioneerx"
[model_providers.pioneerx]
name = "Pioneer"
base_url = "https://api.pioneer.ai/v1"
wire_api = "responses"
env_key = "PIONEER_API_KEY"
Steps to reproduce
CODEX_HOME=~/.codex-pioneer codex exec --skip-git-repo-check 'say hi'
# -> ERROR: stream disconnected before completion: response.failed event received (x retries)
Evidence it is NOT the provider
All tests below were run within the same minute, same key, same account.
1. Direct curl to the provider — succeeds (6/6):
curl -sS -X POST "https://api.pioneer.ai/v1/responses" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"model":"gpt-5.5","input":"hi","stream":true}'
# -> event: response.created ... event: response.completed HTTP 200, output "OK"
Works streaming and non-streaming, for OpenAI-backed (gpt-5.5) and Anthropic-backed (claude-*) models.
2. curl replaying Codex's EXACT captured body + headers — succeeds.
I captured the full request body Codex sends (via RUST_LOG=codex_client::transport=trace) and POSTed it verbatim with curl --data @body.json plus Codex's headers (openai-beta, originator, session_id, user-agent, Accept: text/event-stream). Result: response.completed, HTTP 200.
3. Codex direct — fails, same minute as the passing curls.
So: identical endpoint + key + payload → curl completed, Codex response.failed.
Captured request shape (what Codex sends)
Top-level keys in the POST body to /v1/responses:
model, instructions (~21KB), input, tools (21), tool_choice="auto",
parallel_tool_calls=true, reasoning={"effort":"xhigh"}, store=false,
stream=true, include=["reasoning.encrypted_content"], service_tier,
prompt_cache_key, text={"verbosity":"low"}, client_metadata
Things ruled out
- Not billing/auth — a 401 would never reach
response.created; auth succeeds and aresp_...id is issued beforeresponse.failed. - Not
wire_api—wire_api = "chat"is rejected by 0.134.0 ("no longer supported");responsesis the only option and is what the working curl uses. - Not the provider id — same failure with the id
pioneerand a custom idpioneerx. - Not a transient outage — deterministic across dozens of attempts over ~24h; curl is simultaneously 100% green.
- A local HTTP/1.1 forwarding proxy — curl through the proxy succeeds, but Codex through the same proxy still fails, which points back at the Codex client.
Sample response IDs (provider-issued, for upstream tracing)
resp_bc3c68835f6d4d57aa9aad4a
resp_66bdf8575aa341e8a3b3eb1e
resp_606dc8f86e4f4a66baf57ac6
resp_54ff6cd3d7964f7f9c0f4f80
Ask
What does Codex do differently from a raw curl of the same body/headers against a wire_api = "responses" provider that would cause the upstream to emit response.failed? Happy to capture additional traces (full RUST_LOG, the exact serialized body) on request.
2 Comments
I noticed your issue because the curl request and replayed Codex request both work, but Codex itself still returns upstream_error.
This looks like an interesting client/provider compatibility case.
I would compare a few things:
If the same request body and headers work outside Codex, the remaining difference may be in how Codex processes the response stream.
Did you find any difference between the successful replay and the actual Codex request?
Is there any workaround to fix it?