fix: handle null output in response.completed streaming events#3331
fix: handle null output in response.completed streaming events#3331xodn348 wants to merge 1 commit into
Conversation
When the server sends `output: null` in the `response.completed` SSE event, the SDK would crash with a TypeError in `parse_response`. This adds two defenses: 1. Defensive null guard in `parse_response` (`response.output or []`) 2. Snapshot fallback in the streaming accumulator — if the completed event has null output but the snapshot accumulated items from `response.output_item.added` events, use those instead of losing them Fixes openai#3321 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9cbc5cf0cd
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| elif event.type == "response.completed": | ||
| completed_response = event.response | ||
| if completed_response.output is None and snapshot.output is not None: # pyright: ignore[reportUnnecessaryComparison] | ||
| completed_response = completed_response.model_copy(update={"output": snapshot.output}) |
There was a problem hiding this comment.
Preserve Pydantic v1 compatibility when copying the response
In environments using Pydantic v1, which this package still supports via pydantic>=1.9.0, <3, Response instances do not have a model_copy method. When a streamed response.completed event has output: null and prior output items were accumulated, this fallback path will raise AttributeError before parsing, so the crash remains for supported Pydantic v1 users. Use the repository's compatibility helper or the v1 copy(update=...) path here.
Useful? React with 👍 / 👎.
Summary
Fixes #3321
When the server sends
output: nullin theresponse.completedSSE event, the SDK crashes with aTypeErrorinparse_responsebecause it iterates overresponse.outputwithout a null check. Existing PRs (e.g. #3327) only add the defensiveor []guard, which prevents the crash but silently discards all output items that were correctly accumulated fromresponse.output_item.addedevents during streaming.This PR adds two targeted fixes:
parse_response—response.output or []prevents theTypeErrorResponseStreamState.accumulate_event— whenresponse.completedhasoutput: null, falls back tosnapshot.output(the items accumulated from priorresponse.output_item.addedevents) so no data is lostChanges
src/openai/lib/_parsing/_responses.py— null-safe iteration overresponse.outputsrc/openai/lib/streaming/responses/_responses.py— snapshot fallback inresponse.completedhandlertests/lib/responses/test_null_output.py— 3 tests covering null output parsing and snapshot fallbackTest plan
parse_responsewithoutput=Nonereturns empty output (no crash)parse_responsewithoutput=[]returns empty output (baseline)response.completedhasoutput=Nonetests/lib/responses/tests pass (8/8)