router-for-me / router-for-me/CLIProxyAPI

Codex HTTP error paths discard upstream headers, losing Retry-After and request IDs

Open
#4,633 0 comments 0 reactions 0 assignees View on GitHub

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.go
  • internal/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-After header cannot influence retry scheduling;
  • downstream clients receive no retry hint and may retry a 502/503 immediately;
  • correlation headers such as x-request-id are 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:

  1. Retry-After remains available to retryAfterFromError / the retry controller.
  2. The API error handler can forward safe retry hints.
  3. Optional response-header passthrough can forward permitted correlation headers.
  4. 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: 7 preserves 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.