Client or integration
Codex App
Area
Proxy and routing
Summary
A native OpenAI Responses stream can return HTTP 200 and partial SSE data, then fail while OpenCodex reads the upstream body with a socket reset such as ECONNRESET.
Codex correctly treats the resulting stream disconnected before completion: Transport error: network error: error decoding response body as retryable and replays the logical request. OpenCodex should not replay a partially delivered stream because that could duplicate tool calls or other side effects.
The routing side effect is incorrect: the passthrough inspection path converts a mid-stream body-read failure into synthetic status 502 and records it through recordCodexUpstreamOutcome. Repeated client retries or concurrent streams can then reach upstreamFailoverThreshold, soft-avoid a healthy credential, clear thread affinity, and promote another account even though no account-specific HTTP rejection occurred.
Expected behavior:
- Keep the synthetic mid-stream 502 in request diagnostics.
- Do not apply that synthetic transport terminal to account failure streak, cooldown, affinity, or active-account selection.
- Release only a quota-probe lease owned by the interrupted request.
- Continue recording actual HTTP
429/402/5xx and semantic SSE response.failed outcomes.
- Do not replay the partially delivered request inside OpenCodex; leave bounded retry to Codex.
- Preserve the selected account for the Codex retry unless an actual account-specific rejection occurs.
- Record enough correlation-safe metadata to distinguish upstream body-read failure, downstream pipe failure, client cancellation, and terminal delivery.
Relevant source:
src/server/relay.ts: passthrough inspection maps body-read failure to a synthetic 502 terminal.
src/server/responses/core.ts: native passthrough terminal recording forwards that synthetic status to account routing.
src/codex/routing.ts: repeated transient outcomes can clear affinity and promote another account.
structure/04_transports-and-sidecars.md: mid-stream SSE failures are intentionally not replayed by the proxy.
Required regression coverage:
- HTTP 200 SSE emits a partial delta, then its body throws
ECONNRESET three times for the same thread.
- Each request remains observable as a synthetic mid-stream failure, but account health, affinity, and active selection remain unchanged.
- A held scoped or account-wide probe lease is released exactly once.
- An actual SSE
response.failed with status 502 still records an account failure.
- A client cancellation remains distinct and does not become an upstream failure.
- No extra upstream request is sent by OpenCodex after partial delivery.
Related: #914 handles DNS/reachability failures before response headers; this issue handles failures after HTTP 200 and partial body delivery. #913 covers compact failover only after an actual upstream 429/402. The same client-visible error is tracked upstream in openai/codex#29087.
Reproduction
- Configure OpenAI Codex-login pool routing and bind a thread to account A.
- Return HTTP 200 with
text/event-stream from the OpenAI upstream.
- Deliver at least one valid SSE delta, then make the upstream body reader throw an
ECONNRESET-shaped error before response.completed.
- Let Codex retry the request several times or reproduce the same failure concurrently.
Current: OpenCodex records synthetic 502 account failures. At the configured threshold it can clear A's affinity or promote another account without an actual HTTP rejection.
Expected: Codex can retry, but OpenCodex keeps account routing state unchanged and never replays the partial stream itself.
Version
2.10.0; the relevant passthrough terminal and routing behavior remained on dev at c72acb3e368d2613c41d6d2b15a771895843f03f when checked on 2026-08-03.
Operating system
Windows 11 Pro 10.0.26200. The account-outcome classification issue is platform-independent; the observed resets occurred in the Windows native passthrough path.
Provider and model
OpenAI (Codex login / forward account pool); native Codex Responses streaming.
Logs or error output
stream disconnected before completion: Transport error: network error: error decoding response body
TypeError: The socket connection was closed unexpectedly
code: ECONNRESET
Screenshots and supporting files
None. Exact request IDs, thread IDs, account identifiers, quota values, and timestamps are intentionally omitted.
Redacted configuration
{
"providers": {
"openai": {
"adapter": "openai-responses",
"authMode": "forward",
"codexAccountMode": "pool"
}
},
"upstreamFailoverThreshold": 3
}
Checks
Client or integration
Codex App
Area
Proxy and routing
Summary
A native OpenAI Responses stream can return HTTP 200 and partial SSE data, then fail while OpenCodex reads the upstream body with a socket reset such as
ECONNRESET.Codex correctly treats the resulting
stream disconnected before completion: Transport error: network error: error decoding response bodyas retryable and replays the logical request. OpenCodex should not replay a partially delivered stream because that could duplicate tool calls or other side effects.The routing side effect is incorrect: the passthrough inspection path converts a mid-stream body-read failure into synthetic status 502 and records it through
recordCodexUpstreamOutcome. Repeated client retries or concurrent streams can then reachupstreamFailoverThreshold, soft-avoid a healthy credential, clear thread affinity, and promote another account even though no account-specific HTTP rejection occurred.Expected behavior:
429/402/5xxand semantic SSEresponse.failedoutcomes.Relevant source:
src/server/relay.ts: passthrough inspection maps body-read failure to a synthetic 502 terminal.src/server/responses/core.ts: native passthrough terminal recording forwards that synthetic status to account routing.src/codex/routing.ts: repeated transient outcomes can clear affinity and promote another account.structure/04_transports-and-sidecars.md: mid-stream SSE failures are intentionally not replayed by the proxy.Required regression coverage:
ECONNRESETthree times for the same thread.response.failedwith status 502 still records an account failure.Related: #914 handles DNS/reachability failures before response headers; this issue handles failures after HTTP 200 and partial body delivery. #913 covers compact failover only after an actual upstream 429/402. The same client-visible error is tracked upstream in openai/codex#29087.
Reproduction
text/event-streamfrom the OpenAI upstream.ECONNRESET-shaped error beforeresponse.completed.Current: OpenCodex records synthetic 502 account failures. At the configured threshold it can clear A's affinity or promote another account without an actual HTTP rejection.
Expected: Codex can retry, but OpenCodex keeps account routing state unchanged and never replays the partial stream itself.
Version
2.10.0; the relevant passthrough terminal and routing behavior remained ondevatc72acb3e368d2613c41d6d2b15a771895843f03fwhen checked on 2026-08-03.Operating system
Windows 11 Pro 10.0.26200. The account-outcome classification issue is platform-independent; the observed resets occurred in the Windows native passthrough path.
Provider and model
OpenAI (Codex login / forward account pool); native Codex Responses streaming.
Logs or error output
Screenshots and supporting files
None. Exact request IDs, thread IDs, account identifiers, quota values, and timestamps are intentionally omitted.
Redacted configuration
{ "providers": { "openai": { "adapter": "openai-responses", "authMode": "forward", "codexAccountMode": "pool" } }, "upstreamFailoverThreshold": 3 }Checks