From ed1bc3f0d3ba14c8f7c50bd0c7e4cc961d0d7d80 Mon Sep 17 00:00:00 2001 From: nileshpatil6 Date: Sun, 3 May 2026 12:42:21 +0530 Subject: [PATCH] fix(exceptions): handle non-integer status_code in MidStreamFallbackError When a CustomLLM handler raises RateLimitError inside astreaming(), the error propagates through the streaming pipeline and hits MidStreamFallbackError.__init__. In some code paths the original exception's status_code attribute is a non-integer string (e.g. 'litellm_error'), causing int() to raise ValueError and crash with HTTP 500 instead of triggering the fallback chain. Wrap both int() calls with try/except (ValueError, TypeError) and fall back to 503 so the fallback mechanism can engage normally. Adds regression test: test_midstream_fallback_error_non_integer_status_code verifies status_code and response.status_code both resolve to 503. Fixes #26913 --- litellm/exceptions.py | 14 +++++++++++-- .../test_exception_header_preservation.py | 21 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/litellm/exceptions.py b/litellm/exceptions.py index 8b005291556..825ae2528d8 100644 --- a/litellm/exceptions.py +++ b/litellm/exceptions.py @@ -955,7 +955,12 @@ class MidStreamFallbackError(ServiceUnavailableError): # type: ignore is_pre_first_chunk: bool = False, ): original_status = getattr(original_exception, "status_code", None) - self.status_code = int(original_status) if original_status is not None else 503 + try: + self.status_code = ( + int(original_status) if original_status is not None else 503 + ) + except (ValueError, TypeError): + self.status_code = 503 self.message = f"litellm.MidStreamFallbackError: {message}" self.model = model self.llm_provider = llm_provider @@ -997,7 +1002,12 @@ class MidStreamFallbackError(ServiceUnavailableError): # type: ignore ) # Restore the propagated status and original response/request objects - self.status_code = int(original_status) if original_status is not None else 503 + try: + self.status_code = ( + int(original_status) if original_status is not None else 503 + ) + except (ValueError, TypeError): + self.status_code = 503 self.response = _saved_response self.request = _saved_request self.message = _saved_message diff --git a/tests/test_litellm/test_exception_header_preservation.py b/tests/test_litellm/test_exception_header_preservation.py index 6ea478c633b..bafa1ad38d3 100644 --- a/tests/test_litellm/test_exception_header_preservation.py +++ b/tests/test_litellm/test_exception_header_preservation.py @@ -254,6 +254,27 @@ class TestExceptionAttributes: assert midstream_fallback.response.status_code == 503 assert str(midstream_fallback.response.request.url) == "https://openai.com/v1/" + def test_midstream_fallback_error_non_integer_status_code(self): + """ + MidStreamFallbackError must not crash when original_exception.status_code + is a non-integer string (e.g. 'litellm_error'). Before the fix, int() + raised ValueError and the error handler returned HTTP 500 instead of + engaging the fallback chain. + """ + + class _FakeException(Exception): + status_code = "litellm_error" + + midstream_error = MidStreamFallbackError( + message="stream broke", + model="gpt-4o-mini", + llm_provider="openai", + original_exception=_FakeException("boom"), + ) + + assert midstream_error.status_code == 503 + assert midstream_error.response.status_code == 503 + class TestProxyHeaderExtraction: """Test that proxy correctly extracts headers from exceptions."""