From 6af693de364166cb9c2b5056c3db26b61a3b5cb1 Mon Sep 17 00:00:00 2001 From: Dominic Feliton <37809476+dominicfeliton@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:24:28 -0800 Subject: [PATCH] (fix): empty response + vllm streaming (#17516) * Fix empty response + vllm streaming * Add unit test --- litellm/llms/openai/openai.py | 4 +-- .../llms/openai/test_openai_empty_response.py | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/litellm/llms/openai/openai.py b/litellm/llms/openai/openai.py index 20842525e59..bb9225fc79b 100644 --- a/litellm/llms/openai/openai.py +++ b/litellm/llms/openai/openai.py @@ -444,7 +444,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM): else: headers = {} response = raw_response.parse() - if not hasattr(response, "model_dump"): + if not data.get("stream") and not hasattr(response, "model_dump"): raise OpenAIError( status_code=500, message=f"Empty or invalid response from LLM endpoint. Received: {response!r}. Check the reverse proxy or model server configuration.", @@ -482,7 +482,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM): else: headers = {} response = raw_response.parse() - if not hasattr(response, "model_dump"): + if not data.get("stream") and not hasattr(response, "model_dump"): raise OpenAIError( status_code=500, message=f"Empty or invalid response from LLM endpoint. Received: {response!r}. Check the reverse proxy or model server configuration.", diff --git a/tests/test_litellm/llms/openai/test_openai_empty_response.py b/tests/test_litellm/llms/openai/test_openai_empty_response.py index fb42918f381..d1692bdf9bd 100644 --- a/tests/test_litellm/llms/openai/test_openai_empty_response.py +++ b/tests/test_litellm/llms/openai/test_openai_empty_response.py @@ -95,3 +95,33 @@ class TestEmptyResponseHandling: assert response == mock_response assert headers == {"x-request-id": "123"} + + def test_sync_streaming_response_passes_through_without_model_dump(self): + """ + Test that streaming responses (which don't have model_dump) pass through + correctly without raising an error. This validates the fix for VLLM streaming. + """ + openai_chat = OpenAIChatCompletion() + + # Create a mock response WITHOUT model_dump (like an AsyncStream/Iterator) + mock_stream = MagicMock(spec=[]) # spec=[] means no attributes + + mock_raw_response = MagicMock() + mock_raw_response.headers = {"x-request-id": "123"} + mock_raw_response.parse.return_value = mock_stream + + mock_client = MagicMock() + mock_client.chat.completions.with_raw_response.create.return_value = ( + mock_raw_response + ) + + # Key: data has stream=True - this should bypass the model_dump check + headers, response = openai_chat.make_sync_openai_chat_completion_request( + openai_client=mock_client, + data={"messages": [{"role": "user", "content": "test"}], "stream": True}, + timeout=30, + logging_obj=MagicMock(), + ) + + assert response == mock_stream + assert headers == {"x-request-id": "123"}