Skip to content

fix(codex): raise RuntimeError when response.output is None (Cloudflare/non-SSE body) - #34642

Closed
rdasilva1016-ui wants to merge 1 commit into
NousResearch:mainfrom
rdasilva1016-ui:fix/codex-cloudflare-html-response
Closed

fix(codex): raise RuntimeError when response.output is None (Cloudflare/non-SSE body)#34642
rdasilva1016-ui wants to merge 1 commit into
NousResearch:mainfrom
rdasilva1016-ui:fix/codex-cloudflare-html-response

Conversation

@rdasilva1016-ui

Copy link
Copy Markdown
Contributor

Summary

When the ChatGPT Codex backend serves a Cloudflare challenge page or any non-SSE HTML body (gateway error, temporary block), the OpenAI SDK's stream parser silently leaves response.output as None rather than raising an exception.

This None propagates to _normalize_codex_response which tries to iterate output, resulting in:

TypeError: 'NoneType' object is not iterable

The conversation loop classifies TypeError as is_local_validation_error (a programming bug, non-retryable) and immediately triggers the fallback chain. The error message surfaces to users as the cryptic 'NoneType' object is not iterable with no indication of the real cause.

Root Cause

Confirmed via agent.log: the Codex endpoint chatgpt.com/backend-api/codex was serving a Cloudflare JS challenge page when Hermes exceeded the per-IP request rate from the local gateway. The Cloudflare page was being silently swallowed by the SDK's stream parser and exposed downstream as output=None.

Fix

Add a guard in run_codex_stream immediately after stream.get_final_response() that:

  1. Detects output is None (distinct from output == [] which the existing PATCH already handles)
  2. Includes any streamed text as a diagnostic hint so the Cloudflare HTML is visible in logs
  3. Raises RuntimeError instead of TypeError

RuntimeError is classified as retryable by the conversation loop, giving the retry mechanism a chance to recover before triggering the fallback.

Before / After

Before: TypeError: 'NoneType' object is not iterable — classified as non-retryable local bug, misleading, immediately falls back.

After: RuntimeError: Codex Responses stream completed but response.output is None — the backend may have returned a non-SSE body (Cloudflare challenge, gateway error page, or empty response). Streamed text before failure: '<html>... — classified as retryable, descriptive, includes diagnostic hint.

Test

# Before fix: raises TypeError
# After fix: raises RuntimeError with descriptive message
response = SimpleNamespace(output=None, status='completed')
_out = getattr(response, 'output', None)
if _out is None:
    raise RuntimeError("Codex Responses stream ... response.output is None")

Related: #21444 (gpt-5.5 silent reject pattern on chatgpt.com backend)

…re/non-SSE body)

When the ChatGPT Codex backend serves a Cloudflare challenge page or any
non-SSE HTML body, the OpenAI SDK's stream parser silently leaves
response.output as None rather than raising an exception.  This None
propagates to _normalize_codex_response which iterates output, causing
a TypeError: 'NoneType' object is not iterable.

The conversation loop classifies TypeError as is_local_validation_error
(a programming bug, non-retryable) and immediately triggers the fallback
chain.  While the fallback itself works correctly, the error message is
misleading ('NoneType object is not iterable') and the TypeError
classification wastes a retry slot.

Fix: add a guard in run_codex_stream after get_final_response() that
detects output=None, includes any streamed text as a diagnostic hint in
the message (useful for identifying Cloudflare pages in logs), and raises
RuntimeError instead.  RuntimeError is classified as retryable by the
conversation loop, which gives the retry logic a chance to recover before
falling back.

Root cause confirmed via agent.log: the Codex endpoint
chatgpt.com/backend-api/codex was serving a Cloudflare JS challenge page
when Hermes exceeded the per-IP request rate from the local gateway.

Reproducer: any session that exhausts the Cloudflare challenge threshold
on the Codex backend will manifest as a TypeError in the conversation
loop with summary="'NoneType' object is not iterable".

Fixes NousResearch#31093
@alt-glitch alt-glitch added type/bug Something isn't working codex provider/openai OpenAI / Codex Responses API comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have duplicate This issue or pull request already exists labels May 29, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Superseded by merged #32963 — the canonical Codex null-output fix. The current run_codex_stream no longer calls stream.get_final_response() at all; it uses _consume_codex_event_stream() which builds its own response object and is structurally immune to output=None. The code path this PR guards no longer exists on main.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for this — closing as already fixed on main.

The Codex null-output crash (response.completed with output: null from the chatgpt.com backend → TypeError: 'NoneType' object is not iterable → surfaced as "non-retryable HTTP None") is resolved by commits already on main:

  • cb38ce28c — drop the SDK responses.stream() helper and consume events directly, rebuilding output from response.output_item.done events so the null terminal-event output is never iterated (refactor(codex): drop SDK responses.stream() helper; consume events directly #33042).
  • 43a3f119f — recover Codex streams with null output.
  • dc9d677d5 — classify TypeError('NoneType … not iterable') as a retryable provider-shape error so retry/fallback runs instead of killing the turn.

Your fix targets the same path that's now hardened upstream, so there's nothing left to merge here. Your authorship is preserved in your branch; I'm crediting your report in the umbrella issue #33932 (now closed). Appreciate the contribution.

@teknium1 teknium1 closed this Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have provider/openai OpenAI / Codex Responses API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants