Xiaobai
Developer · Builder
Building AI engineering systems, developer tools and long-term digital assets at XBSTACK.
About Xiaobai & XBSTACK →
Why Codex CLI Turns response.failed Into idle timeout waiting for SSE: Reproduced on 0.153.4 and 0.154.0
Why does Codex CLI keep waiting after an SSE response.failed event and finally report idle timeout waiting for SSE? XBSTACK independently reproduces the behavior on 0.153.4 and the current stable 0.154.0 with a local loopback fixture, version matrix, diagnostic boundaries, and temporary handling guidance.
Why Codex CLI Turns response.failed Into idle timeout waiting for SSE
If Codex CLI ends with:
stream disconnected before completion: idle timeout waiting for SSE
do not automatically conclude that the upstream server returned nothing. XBSTACK independently reproduced a different failure shape on Codex CLI 0.153.4 and 0.154.0: the server had already sent a terminal response.failed containing a real server_error, but because the underlying socket stayed open, Codex kept waiting for EOF until the stream idle timeout fired and replaced the original failure with idle timeout waiting for SSE.
That distinction matters in production. If you keep only the final Codex error, a provider failure or capacity rejection can look like a generic network timeout, sending debugging in the wrong direction.
Result: 0.154.0 is still reproducible
XBSTACK ran the same local loopback fixture against both versions:
| Codex CLI | Server behavior | Original error preserved | Idle timeout shown |
|---|---|---|---|
0.153.4 | close immediately after response.failed | yes | no |
0.153.4 | keep socket open | no | yes |
0.154.0 | close immediately after response.failed | yes | no |
0.154.0 | keep socket open | no | yes |
The open-socket case exited after roughly 1.08 seconds on 0.153.4 and 1.12 seconds on 0.154.0. Those timings are not a benchmark: the fixture deliberately sets stream_idle_timeout_ms=800 so the behavior appears quickly.
The EOF case preserves the real marker:
stream disconnected before completion: XBSTACK_LOCAL_TERMINAL_FAILURE
The hold-open case instead surfaces:
stream disconnected before completion: idle timeout waiting for SSE
The SSE event sent by the server is otherwise identical.
What the fixture proves
The local server returns HTTP 200 with Content-Type: text/event-stream:
HTTP/1.1 200 OK
Content-Type: text/event-stream
It then sends a terminal failure:
event: response.failed
data: {
"type": "response.failed",
"response": {
"status": "failed",
"error": {
"code": "server_error",
"message": "XBSTACK_LOCAL_TERMINAL_FAILURE"
}
}
}
Case A closes the connection immediately. Case B leaves it open.
The resulting path is:
HTTP 200
↓
SSE response.failed
↓
Codex has already parsed a real server_error
↓
socket remains open
↓
Codex continues waiting for EOF
↓
stream idle timeout fires
↓
user sees idle timeout waiting for SSE
So the problem is not that the server was silent. The problem is that a later transport timeout can replace useful terminal-failure information.
Why this creates bad debugging decisions
If the real provider error says something like:
server_error: backend capacity unavailable
but the final Codex message only says:
idle timeout waiting for SSE
it is tempting to increase idle timeouts, add stream retries, blame DNS/TLS/proxies, reinstall Codex, or shrink context. None of those changes necessarily addresses the first failure.
Changing stream_idle_timeout_ms is therefore not a root fix. A larger value delays the replacement; a smaller value makes the replacement happen sooner.
How to tell whether your incident matches this failure shape
Keep at least four layers of evidence:
- HTTP status;
- SSE event type;
response.failed.response.error;- final Codex CLI error.
This sequence strongly matches the reproduced behavior:
HTTP 200
response.failed: server_error / <real message>
... socket stays open ...
Codex: idle timeout waiting for SSE
If no response.failed event arrives at all and the stream simply goes quiet, that is a different, genuine idle-timeout scenario.
Fully local reproduction
The XBSTACK reproducer requires no model or API account. It uses the Python standard library, a loopback HTTP server, and a fresh temporary CODEX_HOME for every case.
python3 repro.py \
--codex /Applications/ChatGPT.app/Contents/Resources/codex \
--output logs/result.json
It automatically runs:
Case A: response.failed -> EOF
Case B: response.failed -> keep socket open
and records whether the original marker is preserved and whether the idle-timeout string appears.
The EOF case records:
{
"original_error_preserved": true,
"idle_timeout_reported": false
}
The hold-open case records:
{
"original_error_preserved": false,
"idle_timeout_reported": true
}
Why 0.154.0 matters
The upstream issue was originally reported against 0.153.4, but Codex 0.154.0 shipped on September 9. A current troubleshooting page must answer the obvious question: did upgrading already fix it?
XBSTACK therefore ran the exact same fixture against the official OpenAI Codex GitHub stable release rust-v0.154.0 Apple Silicon binary.
It still reproduced.
As of September 12, 2026, under the controlled conditions above:
Upgrading to 0.154.0 is not a verified fix for this failure shape.
Future stable releases need to be retested rather than inferred from alpha builds or moving main.
The upstream issue includes a proposed patch, not an official released fix
Issue #43140 includes source analysis and a candidate patch whose core idea is to stop the producer after a terminal response.failed has already been classified instead of continuing to wait for SSE EOF.
That direction is consistent with the control experiment, but three states must remain separate:
- the upstream reporter tested a patch locally;
- XBSTACK independently reproduced the bug behavior;
- OpenAI merges and releases an official fix.
Only the first two are confirmed here. The issue remained open when checked on September 12, so this article does not tell users that a released version has officially fixed it.
Production handling now
Preserve the first terminal failure
For custom providers, Azure OpenAI, gateways, or proxies, keep the raw SSE event whenever possible. The first terminal error is often more diagnostic than a timeout minutes later.
Correlate provider request IDs
Store request IDs, region/capacity metadata, retry hints, and provider error categories alongside the Codex run or trace ID.
Do not blame every reconnect on this bug
This article confirms only:
terminal response.failed + socket remains open
It does not prove that all of the following come from the SSE consumer:
all server_error responses
all no healthy upstream errors
all TLS failures
all Azure capacity failures
all Codex reconnects
Treat source patches as candidate fixes until released
If you maintain a custom Codex build, the upstream patch and regression tests are worth evaluating. For production teams using official binaries, the safer release test is:
new stable release
↓
run the repro
↓
EOF case preserves original error
↓
open-socket case also preserves original error immediately
↓
then mark the issue fixed for your environment
Reliability first, security second
This is primarily a reliability and observability problem, not a reason to turn every Codex failure into a generic AI-security article.
There is still a security/governance implication: if an agent runtime replaces the real execution failure with a secondary timeout, audit trails, alerting, automatic recovery, and incident classification become less trustworthy. Accurate failure preservation is part of runtime control and incident response.
That is why this page belongs in the Codex / AI Tools Lab troubleshooting path while linking into the broader AI Agent Security themes of audit, observability, and runtime control.
Final takeaway
As of September 12, 2026, XBSTACK independently confirms:
- Codex CLI
0.153.4is affected; - Codex CLI
0.154.0is still affected; - EOF immediately after
response.failedpreserves the original error; - keeping the socket open can make Codex wait until idle timeout;
- the final
idle timeout waiting for SSEcan hide the real server failure; - changing the idle timeout is not a root fix;
- the proposed upstream patch is not yet an official released fix.
If you are debugging Codex SSE reconnects, the first question should be: did the server already send response.failed before the timeout appeared?
For adjacent streaming failures, compare the Responses API stream-abort tool-call loss case. If you are using Astra or a custom provider, the GPT-6 Astra API guide covers the surrounding provider and migration boundaries. Runtime troubleshooting is grouped in AI Tools Lab, while authorization, audit, and runtime-control security belongs in AI Agent Security.
Primary evidence
- Upstream issue: https://github.com/openai/codex/issues/43140
- Codex releases: https://github.com/openai/codex/releases
- XBSTACK independent reproduction: https://github.com/xbstack/codex-response-failed-idle-timeout-repro
More to Explore
Topic hub →AI Engineering Weekly
Production changes, real failures, experiments and new XBSTACK assets.
DISCUSSION
Questions, verification and corrections
Sign in to comment. Every new comment is reviewed before publication; while pending, it is visible only to you and the administrator.