Skip to content

fix(responses): guard against null item/text in stream accumulator and output_text - #3628

Open
Xsidz wants to merge 2 commits into
openai:mainfrom
Xsidz:fix/responses-null-guards
Open

fix(responses): guard against null item/text in stream accumulator and output_text#3628
Xsidz wants to merge 2 commits into
openai:mainfrom
Xsidz:fix/responses-null-guards

Conversation

@Xsidz

@Xsidz Xsidz commented Aug 16, 2026

Copy link
Copy Markdown

Summary

Fixes #3125 and #3011 — both are null-safety gaps in the Responses API path.

#3125 — stream accumulator crashes on item=null

ResponseStreamState._accumulate_event accessed event.item.type unconditionally for response.output_item.added events. OpenAI-compatible providers can emit this event with item: null, causing AttributeError: 'NoneType' object has no attribute 'type'. Added a if event.item is None: pass guard before the type dispatch.

#3011Response.output_text crashes on text=null

The output_text property appended content.text without a null check. Models such as gpt-oss-safeguard-120b can return output_text content blocks with text: null, causing TypeError during "".join(texts). Added and content.text is not None to the filter condition.

Test plan

  • tests/test_models.py, tests/test_transform.py, tests/lib/responses/: 121 passed, 0 failures.
  • Ruff lint: all checks passed.

…d output_text

Fixes openai#3125: response.output_item.added with item=null crashed with
AttributeError because event.item.type was accessed unconditionally.
Skip the item when null.

Fixes openai#3011: Response.output_text crashed with TypeError when a content
block had text=null. Filter out null text values before joining.
@Xsidz
Xsidz requested a review from a team as a code owner August 16, 2026 17:21
Copilot AI lite review requested due to automatic review settings August 16, 2026 17:21

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@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: b9961b6ec5

ℹ️ 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".

Comment on lines +331 to +332
if event.item is None:
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve output indexes when an item is null

When a compatible provider emits a null item and then continues with another output item, this pass leaves snapshot.output one element shorter than the server's output indexes. Subsequent response.content_part.added, text-delta, or function-call-delta events index this list using event.output_index, so they can raise IndexError or update the wrong item. Preserve the missing slot's index or track and ignore dependent events by server index rather than shifting later outputs.

Useful? React with 👍 / 👎.

Comment on lines +489 to 490
if content.type == "output_text" and content.text is not None:
texts.append(content.text)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard null text before structured parsing

For callers using responses.parse(..., text_format=...) or responses.stream(..., text_format=...), parse_response() processes the response before this property can be used and still calls parse_text(item.text, ...) unconditionally. The same output_text block with text: null therefore passes None to Pydantic's JSON parser and raises, so the affected response remains unusable in structured-output paths; skip parsing or normalize null text in parse_response() as well.

Useful? React with 👍 / 👎.

…runtime behavior

The accumulator guard in _responses.py already handles event.item being
None; make the type annotation reflect this so type-checkers don't flag
the null check as dead code.
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.

Responses stream accumulator crashes when response.output_item.added has item=None

2 participants