fix(responses): guard against null item/text in stream accumulator and output_text - #3628
fix(responses): guard against null item/text in stream accumulator and output_text#3628Xsidz wants to merge 2 commits into
Conversation
…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.
There was a problem hiding this comment.
💡 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".
| if event.item is None: | ||
| pass |
There was a problem hiding this comment.
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 👍 / 👎.
| if content.type == "output_text" and content.text is not None: | ||
| texts.append(content.text) |
There was a problem hiding this comment.
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.
Summary
Fixes #3125 and #3011 — both are null-safety gaps in the Responses API path.
#3125 — stream accumulator crashes on
item=nullResponseStreamState._accumulate_eventaccessedevent.item.typeunconditionally forresponse.output_item.addedevents. OpenAI-compatible providers can emit this event withitem: null, causingAttributeError: 'NoneType' object has no attribute 'type'. Added aif event.item is None: passguard before the type dispatch.#3011 —
Response.output_textcrashes ontext=nullThe
output_textproperty appendedcontent.textwithout a null check. Models such asgpt-oss-safeguard-120bcan returnoutput_textcontent blocks withtext: null, causingTypeErrorduring"".join(texts). Addedand content.text is not Noneto the filter condition.Test plan
tests/test_models.py,tests/test_transform.py,tests/lib/responses/: 121 passed, 0 failures.