router-for-me / router-for-me/CLIProxyAPI
Codex HTTP error paths discard upstream headers, losing Retry-After and request IDs
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 52.5k
- Forks
- 7.9k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 60
Description
Problem
The Codex HTTP executor records upstream response headers for logging, but when a non-2xx response is converted into statusErr, only the status code and body are retained:
internal/runtime/executor/codex_executor_execute.gointernal/runtime/executor/codex_executor_stream.go- the other HTTP call sites that invoke
newCodexStatusErr(status, body)
This drops safe upstream error metadata before the auth retry layer and API handler can inspect it. In particular:
- an upstream
Retry-Afterheader cannot influence retry scheduling; - downstream clients receive no retry hint and may retry a 502/503 immediately;
- correlation headers such as
x-request-idare unavailable for diagnostics even when response-header passthrough is enabled.
The Codex WebSocket path already has the required shape: statusErrWithHeaders implements Headers() and parseCodexWebsocketError retains parsed headers. The HTTP path does not.
Expected behavior
Codex HTTP non-2xx errors should retain an immutable clone of the upstream headers for internal retry metadata and diagnostics. Before any header is exposed downstream, the API boundary must apply the existing safe upstream-header filter so credentials, hop-by-hop fields, response-body metadata, cookies, gateway markers, and CPA-reserved headers cannot leak.
At minimum:
Retry-Afterremains available toretryAfterFromError/ the retry controller.- The API error handler can forward safe retry hints.
- Optional response-header passthrough can forward permitted correlation headers.
- Existing error-body classification and status mapping remain unchanged.
Suggested implementation
Add a header-aware Codex status-error constructor, or wrap newCodexStatusErr(...) in statusErrWithHeaders at every HTTP non-2xx call site. Preserve an immutable internal clone, then reuse the existing API-boundary upstream-header filtering before optional passthrough.
Regression tests
- Codex non-stream HTTP 503 with
Retry-After: 7preserves a 7-second retry hint. - Codex streaming bootstrap HTTP 503 preserves the same hint.
- A permitted request-id header is present only when passthrough is enabled.
- Sensitive or unapproved upstream headers remain absent.
- The existing WebSocket behavior remains unchanged.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with internal/runtime/executor/codex_executor_execute.go and internal/runtime/executor/codex_executor_stream.go, then compare the WebSocket statusErrWithHeaders and parseCodexWebsocketError flow. Trace retryAfterFromError and the existing API-boundary upstream-header filter before updating every HTTP newCodexStatusErr call site. Done means both HTTP paths preserve Retry-After, safe passthrough works only when enabled, sensitive headers stay hidden, and the listed regression cases pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100