Skip to content

fix: guard against null output in parse_response and output_text property#3404

Open
adhavan18 wants to merge 2 commits into
openai:mainfrom
adhavan18:fix/null-output-crash
Open

fix: guard against null output in parse_response and output_text property#3404
adhavan18 wants to merge 2 commits into
openai:mainfrom
adhavan18:fix/null-output-crash

Conversation

@adhavan18

@adhavan18 adhavan18 commented Jun 15, 2026

Copy link
Copy Markdown

Fixes #3325 and #3063.

Problem

Two crashes in the Responses API when the server returns unexpected null values:

  1. Some backends send output: null in the final response.completed event even when output items were already streamed. parse_response and Response.output_text both iterate response.output directly → TypeError: 'NoneType' object is not iterable.
  2. When an output_text content item has text: null, parse_response passes None to the structured parser and output_text concatenates None into the string.

Fix

  • _parsing/_responses.py — iterate response.output or []; skip structured parsing when item.text is None
  • types/responses/response.py — same or [] guard in the output_text property; skip content items where text is None
  • lib/streaming/responses/_responses.py — when response.completed arrives with output: null, fall back to the accumulated snapshot output instead of parsing an empty list

Test

All existing tests in tests/lib/responses/ pass.

…erty

When the Responses API returns `output: null` in a `response.completed`
event (observed with the chatgpt.com Codex backend), iterating
`response.output` raised `TypeError: 'NoneType' object is not iterable`.
A second related case is `output_text` content items whose `text` field
is `null`, which caused `parse_response` to pass `None` to structured
text parsing and `output_text` to concatenate `None` into the result.

Fixes:
- `parse_response` in `lib/_parsing/_responses.py`: iterate
  `response.output or []` so a null list is treated as empty.
- Same function: skip structured parsing for `output_text` items where
  `item.text is None`; set `parsed=None` for those items instead.
- `Response.output_text` property in `types/responses/response.py`:
  iterate `self.output or []` and skip content items with `text is None`.

Adds four regression tests covering all three cases.

Closes openai#3325, openai#3063
@adhavan18 adhavan18 requested a review from a team as a code owner June 15, 2026 07:42

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 49ab38b624

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

output_list: List[ParsedResponseOutputItem[TextFormatT]] = []

for output in response.output:
for output in response.output or []:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve streamed output on null completed payloads

In the streamed Responses path, ResponseStreamState.accumulate_event parses event.response on response.completed (src/openai/lib/streaming/responses/_responses.py:359-364) rather than the accumulated snapshot, so when that final completed event has output=None after earlier output item/text delta events, this new fallback turns the final parsed response into output=[]. In that backend case, stream.get_final_response().output_text and the emitted completed event become empty even though the stream already received valid text; the null completed payload should fall back to the accumulated snapshot instead of discarding it.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant