Confirm this is an issue with the Python library and not an underlying OpenAI API
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
Confirm this is an issue with the Python library and not an underlying OpenAI API
Describe the bug
Summary
parse_response()insrc/openai/lib/_parsing/_responses.pyiteratesresponse.outputwithout checking forNone. The chatgpt.com Codex backend (https://chatgpt.com/backend-api/codex, the one the Codex CLI uses with ChatGPT-account auth) sometimes sendsresponse.output: nullin the consolidatedresponse.completedevent — even when validresponse.output_item.doneevents were streamed earlier in the same response. The SDK then raisesTypeError: 'NoneType' object is not iterableinside the stream accumulator, killing the entire stream before the consumer can read the deltas.Stack trace
Observed wire-level behaviour
Inspecting the SSE events directly (e.g. via
curl) shows the chatgpt.com Codex backend streams the response content correctly viaresponse.output_item.doneevents withitem.type == "message"and populatedcontent, but the trailingresponse.completedevent'sresponse.outputfield isnull. Schema-wise the SDK treatsoutputaslist[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 emptyoutput, or surface a structuredEmptyOutputError— but a bareTypeErrorfrom the deep accumulator path is hard to handle defensively from outside.Suggested fix
One-line defensive iteration in
parse_response:Verified locally — with this patch the stream completes,
get_final_response()returns aResponsewithoutput=[], and consumers that already trackoutput_item.doneevents (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 haveoutput: list.Environment
openai==2.24.0(also reproduces in currentmainper source inspection — same line, same assumption)https://chatgpt.com/backend-api/codex(ChatGPT-account OAuth, as used by the official Codex CLI)gpt-5.5withreasoning.effort: lowRelated upstream cause
The chatgpt.com Codex backend sending
output: nullinresponse.completedwhile having streamed validoutput_item.doneitems 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.