fix(responses): guard empty choices in streaming delta extraction - #32519
fix(responses): guard empty choices in streaming delta extraction#32519ansulev wants to merge 2 commits into
Conversation
_get_delta_string_from_streaming_choices indexes choices[0] without checking for an empty list. Providers such as DeepSeek emit a terminal streaming chunk with "choices": [] (finish/usage chunk), which raises IndexError and kills the /v1/responses stream mid-response when bridging to a chat-completions backend. Every other access in this file already guards with `chunk.choices and ...`; this applies the same guard here.
|
|
Greptile SummaryGuards
Confidence Score: 5/5The change is a minimal, isolated two-line guard that closes an unchecked list index and is accompanied by a focused unit test; no existing behaviour is altered. Both files touch only the streaming iterator's delta-extraction helper. The fix is a single early-return consistent with every other guard already present in the same method's callers, and the new test exercises both branches without making any real network calls. No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/responses/litellm_completion_transformation/streaming_iterator.py | Adds a two-line early-return guard for empty choices in _get_delta_string_from_streaming_choices, consistent with how all other access sites in the file already guard against empty choices. |
| tests/test_litellm/responses/test_streaming_empty_choices.py | New unit test covering both the empty-choices path (returns "") and the normal path (returns delta content); no real network calls, uses inline mock objects only. |
Reviews (1): Last reviewed commit: "test(responses): cover empty-choices gua..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
What
_get_delta_string_from_streaming_choicesinlitellm/responses/litellm_completion_transformation/streaming_iterator.pyindexeschoices[0]without checking for an empty list.
Repro
Proxy config bridging
/v1/responsesto an OpenAI-compatible chat-completions backend(
use_chat_completions_api: true). DeepSeek (tested:deepseek-v4-flashbehind a customapi_base) emits a terminal streaming chunk with"choices": []. Result:The stream dies with
data: {"error": {"message": "list index out of range", ... "code": "500"}}after the content has already streamed.
Fix
Return
""whenchoicesis empty — the samechunk.choices and ...guard every other access inthis file already uses (annotation, reasoning and tool-call paths). Unit test covers both branches.
Tested locally on 1.91.0: with the guard, the same request terminates cleanly with
response.completed+data: [DONE]and usage intact.Note
Supersedes #32468 (same fix, was wrongly targeted at
mainfrom a fork; this one targetslitellm_oss_stagingper the source-branch policy, plus the missing test coverage).