From aa31fceccd5508548173e5746daca71670f0d381 Mon Sep 17 00:00:00 2001 From: SamSi0322 Date: Fri, 10 Apr 2026 11:05:26 -0400 Subject: [PATCH 1/2] Handle error responses embedded in SSE streams When an upstream provider (e.g. sglang) returns an error inside an HTTP 200 streaming response as {"error": {...}}, the chunk parser tried to construct a ModelResponseStream from the error dict, crashing with missing fields. Added an early check for the "error" key in chunks before attempting to parse standard completion fields. When detected, raises a BadRequestError with the upstream error message instead of letting it cascade to a misleading 503 MidStreamFallbackError. Closes #25492 --- litellm/llms/openai/chat/gpt_transformation.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py index c12c6e6ba09..b0d6e17d81f 100644 --- a/litellm/llms/openai/chat/gpt_transformation.py +++ b/litellm/llms/openai/chat/gpt_transformation.py @@ -803,6 +803,18 @@ class OpenAIChatCompletionStreamingHandler(BaseModelResponseIterator): def chunk_parser(self, chunk: dict) -> ModelResponseStream: try: + # Handle error responses embedded in SSE streams (e.g. from sglang) + if "error" in chunk: + error_data = chunk["error"] + error_message = error_data.get("message", str(error_data)) + error_type = error_data.get("type", "") + error_code = error_data.get("code", 500) + raise litellm.BadRequestError( + message=f"Received error in stream: {error_message}", + model=chunk.get("model", ""), + llm_provider=self.custom_llm_provider, + ) + choices = chunk.get("choices", []) choices = self._map_reasoning_to_reasoning_content(choices) From a98d9d59642f3b7a2b97ef000067052a27059050 Mon Sep 17 00:00:00 2001 From: SamSi0322 Date: Fri, 10 Apr 2026 11:56:09 -0400 Subject: [PATCH 2/2] Address Greptile review: handle non-dict error payloads and forward error code - Guard against string error_data (some providers send {"error": "message"} instead of {"error": {"message": ..., "code": ...}}) - Forward the upstream error code via httpx.Response so callers get the correct status code instead of always seeing 400 --- litellm/llms/openai/chat/gpt_transformation.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py index b0d6e17d81f..e269c078536 100644 --- a/litellm/llms/openai/chat/gpt_transformation.py +++ b/litellm/llms/openai/chat/gpt_transformation.py @@ -806,13 +806,17 @@ class OpenAIChatCompletionStreamingHandler(BaseModelResponseIterator): # Handle error responses embedded in SSE streams (e.g. from sglang) if "error" in chunk: error_data = chunk["error"] - error_message = error_data.get("message", str(error_data)) - error_type = error_data.get("type", "") - error_code = error_data.get("code", 500) + if isinstance(error_data, dict): + error_message = error_data.get("message", str(error_data)) + error_code = error_data.get("code", 400) + else: + error_message = str(error_data) + error_code = 400 raise litellm.BadRequestError( message=f"Received error in stream: {error_message}", model=chunk.get("model", ""), llm_provider=self.custom_llm_provider, + response=httpx.Response(status_code=error_code, request=httpx.Request(method="POST", url="")), ) choices = chunk.get("choices", [])