fix(streaming): guard against IndexError in Responses API stream accumulator#2942
fix(streaming): guard against IndexError in Responses API stream accumulator#2942MaxwellCalkin wants to merge 1 commit intoopenai:mainfrom
Conversation
…ream accumulator Fixes IndexError (list index out of range) that occurs intermittently in ResponseStreamState.accumulate_event() and handle_event() when output_index references an item not yet added to the snapshot. This happens when using the Responses API with streaming and tools (e.g., web_search, code_interpreter) or when resuming streams with starting_after. The API may deliver events referencing output indices that have not yet been populated via response.output_item.added. The fix adds bounds checks before accessing snapshot.output[output_index] in both accumulate_event() and handle_event(). When the index is out of bounds, accumulate_event() silently skips the snapshot update (the final response.completed event will have the full data), and handle_event() falls back to emitting the raw event without snapshot enrichment. Fixes openai#2852
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf39cab8d9
ℹ️ 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".
| else: | ||
| events.append(event) |
There was a problem hiding this comment.
Preserve parsed done events when output index is missing
When response.output_text.done arrives with an out-of-bounds output_index, this branch now emits the raw event object, which does not have the parsed field that responses.stream() consumers expect for response.output_text.done events. In the exact tool/resume scenarios this patch targets, user code that accesses event.parsed after checking event.type == "response.output_text.done" will still fail (now with AttributeError instead of IndexError), even though parsing can still be performed from event.text without needing snapshot state.
Useful? React with 👍 / 👎.
Summary
Fixes
IndexError: list index out of rangethat occurs intermittently insideResponseStreamState.accumulate_event()andhandle_event()whenoutput_indexreferences a snapshot output item that has not yet been added.Fixes #2852
Problem
When streaming Responses API events with tools (e.g.,
web_search,code_interpreter) or when resuming a stream viastarting_after, the stream accumulator can crash with:This happens because several event handlers in both
accumulate_event()andhandle_event()accesssnapshot.output[event.output_index]without verifying the index is within bounds. Theresponse.createdevent initializes the snapshot with an empty (or partially populated) output list, and subsequent events likeresponse.content_part.added,response.output_text.delta, orresponse.function_call_arguments.deltamay reference indices not yet populated byresponse.output_item.added.Fix
Adds
event.output_index < len(snapshot.output)bounds checks before everysnapshot.output[event.output_index]access in both methods:accumulate_event()— when the index is out of bounds, the snapshot update is silently skipped. The finalresponse.completedevent contains the full response data regardless, so no information is lost.handle_event()— when the index is out of bounds, the raw (un-enriched) event is emitted to the caller instead of crashing. This preserves the event stream and lets consumers handle the event directly.Affected event types:
response.content_part.addedresponse.output_text.deltaresponse.output_text.doneresponse.function_call_arguments.deltaTest plan
get_final_response()still returns the complete parsed response🤖 Generated with Claude Code