Skip to content

parse_response crashes with TypeError when response.output is null in response.completed event (chatgpt.com Codex backend) #3325

@ApexAspire

Description

@ApexAspire

Confirm this is an issue with the Python library and not an underlying OpenAI API

  • This is an issue with the Python library

Describe the bug

Summary

parse_response() in src/openai/lib/_parsing/_responses.py iterates response.output without checking for None. The chatgpt.com Codex backend (https://chatgpt.com/backend-api/codex, the one the Codex CLI uses with ChatGPT-account auth) sometimes sends response.output: null in the consolidated response.completed event — even when valid response.output_item.done events were streamed earlier in the same response. The SDK then raises TypeError: 'NoneType' object is not iterable inside the stream accumulator, killing the entire stream before the consumer can read the deltas.

Stack trace

File ".../openai/lib/streaming/responses/_responses.py", line 49, in __iter__
    for item in self._iterator:
File ".../openai/lib/streaming/responses/_responses.py", line 57, in __stream__
    events_to_fire = self._state.handle_event(sse_event)
File ".../openai/lib/streaming/responses/_responses.py", line 248, in handle_event
    self.__current_snapshot = snapshot = self.accumulate_event(event)
File ".../openai/lib/streaming/responses/_responses.py", line 360, in accumulate_event
    self._completed_response = parse_response(
File ".../openai/lib/_parsing/_responses.py", line 61, in parse_response
    for output in response.output:
TypeError: 'NoneType' object is not iterable

Observed wire-level behaviour

Inspecting the SSE events directly (e.g. via curl) shows the chatgpt.com Codex backend streams the response content correctly via response.output_item.done events with item.type == "message" and populated content, but the trailing response.completed event's response.output field is null. Schema-wise the SDK treats output as list[ResponseOutputItem] and assumes non-null.

Expected behaviour

The SDK should not crash when a server returns response.output: null. Either coerce to [] and let the consumer / get_final_response() see an empty output, or surface a structured EmptyOutputError — but a bare TypeError from the deep accumulator path is hard to handle defensively from outside.

Suggested fix

One-line defensive iteration in parse_response:

-    for output in response.output:
+    for output in (response.output or []):

Verified locally — with this patch the stream completes, get_final_response() returns a Response with output=[], and consumers that already track output_item.done events (such as the Hermes Agent project and the Codex CLI itself) can backfill the response from their own collected items. No regression on responses that legitimately have output: list.

Environment

  • openai==2.24.0 (also reproduces in current main per source inspection — same line, same assumption)
  • Python 3.11
  • Backend: https://chatgpt.com/backend-api/codex (ChatGPT-account OAuth, as used by the official Codex CLI)
  • Model: gpt-5.5 with reasoning.effort: low

Related upstream cause

The chatgpt.com Codex backend sending output: null in response.completed while having streamed valid output_item.done items earlier looks like a separate backend issue. Flagging it here in case it can be routed internally — there's no public tracker for that backend.


## Optional follow-up comment

If maintainers ask "is this our responsibility since chatgpt.com is an internal backend?":

```markdown
Understood that chatgpt.com/backend-api/codex isn't the canonical OpenAI public API. Still feels worth fixing on the SDK side because (a) it's a one-line defensive change with zero behavioural risk, (b) any future backend that streams output items but consolidates them differently would hit the same crash, and (c) the Codex CLI uses the same SDK against the same backend, so users on Codex CLI are likely seeing this too even if it's only manifested as flaky stream completions for them.
```


### To Reproduce

## Reproduction

```python
from openai import OpenAI

client = OpenAI(
    api_key="<ChatGPT account access_token>",
    base_url="https://chatgpt.com/backend-api/codex",
    default_headers={"OpenAI-Beta": "responses=v1", "originator": "codex_cli_rs"},
)

with client.responses.stream(
    model="gpt-5.5",
    instructions="You are a helpful assistant.",
    input=[{"role": "user", "content": [{"type": "input_text", "text": "What is 2+2?"}]}],
    store=False,
    reasoning={"effort": "low"},
) as stream:
    for event in stream:   # raises here on the response.completed event
        pass
```

### Code snippets

```Python

```

### OS

macOS

### Python version

Python 3.11

### Library version

openai v2.24.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions