From 23f846641836dcd6ee8ee49b55c423b310345b7c Mon Sep 17 00:00:00 2001 From: nightcityblade Date: Fri, 14 Aug 2026 00:04:12 +0800 Subject: [PATCH 1/2] fix(responses): raise on failed chat streams --- .../transformation.py | 12 +++++++ ...responses_transformation_transformation.py | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 579cf83bffa..3001268503f 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -1444,6 +1444,18 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator): ], usage=usage, ) + elif event_type in ("response.failed", "error"): + response_data = parsed_chunk.get("response") or {} + if not isinstance(response_data, dict): + response_data = {} + error_data = response_data.get("error") or parsed_chunk.get("error") or parsed_chunk + error_message = error_data.get("message") if isinstance(error_data, dict) else None + raise litellm.APIError( + status_code=500, + message=error_message or "Responses API stream failed", + llm_provider="", + model=response_data.get("model", ""), + ) else: pass # For any unhandled event types, create a minimal valid chunk or skip diff --git a/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py b/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py index b8bd5c951ee..21a18b2244a 100644 --- a/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py +++ b/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py @@ -18,6 +18,37 @@ from litellm.completion_extras.litellm_responses_transformation.transformation i ) +@pytest.mark.parametrize( + ("chunk", "message"), + [ + ( + { + "type": "response.failed", + "response": { + "model": "gpt-5.6-luna", + "error": {"code": "server_error", "message": "upstream failed"}, + }, + }, + "upstream failed", + ), + ({"type": "error", "code": "server_error", "message": "stream failed"}, "stream failed"), + ( + {"type": "response.failed", "response": "invalid", "error": {"message": "malformed failure"}}, + "malformed failure", + ), + ], +) +def test_response_stream_failure_raises_api_error(chunk, message): + from litellm.completion_extras.litellm_responses_transformation.transformation import ( + OpenAiResponsesToChatCompletionStreamIterator, + ) + + with pytest.raises(litellm.APIError, match=message) as exc_info: + OpenAiResponsesToChatCompletionStreamIterator.translate_responses_chunk_to_openai_stream(chunk) + + assert exc_info.value.status_code == 500 + + def test_convert_chat_completion_messages_to_responses_api_image_input(): from litellm.completion_extras.litellm_responses_transformation.transformation import ( LiteLLMResponsesTransformationHandler, From 7f1352214329cd03497aad9815f95eb33e7afc60 Mon Sep 17 00:00:00 2001 From: nightcityblade Date: Fri, 14 Aug 2026 00:38:33 +0800 Subject: [PATCH 2/2] fix(responses): avoid Final variable reuse --- .../litellm_responses_transformation/transformation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py index 3001268503f..e6a538d49e4 100644 --- a/litellm/completion_extras/litellm_responses_transformation/transformation.py +++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py @@ -1445,16 +1445,16 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator): usage=usage, ) elif event_type in ("response.failed", "error"): - response_data = parsed_chunk.get("response") or {} - if not isinstance(response_data, dict): - response_data = {} - error_data = response_data.get("error") or parsed_chunk.get("error") or parsed_chunk + failure_response_data = parsed_chunk.get("response") or {} + if not isinstance(failure_response_data, dict): + failure_response_data = {} + error_data = failure_response_data.get("error") or parsed_chunk.get("error") or parsed_chunk error_message = error_data.get("message") if isinstance(error_data, dict) else None raise litellm.APIError( status_code=500, message=error_message or "Responses API stream failed", llm_provider="", - model=response_data.get("model", ""), + model=failure_response_data.get("model", ""), ) else: pass