mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix: tolerate invalid midstream fallback status
This commit is contained in:
parent
ebd335da67
commit
fbb21ae0c9
2 changed files with 66 additions and 3 deletions
|
|
@ -941,6 +941,24 @@ class BlockedPiiEntityError(Exception):
|
|||
|
||||
|
||||
class MidStreamFallbackError(ServiceUnavailableError): # type: ignore
|
||||
@staticmethod
|
||||
def _get_status_code(original_exception: Optional[Exception]) -> int:
|
||||
if original_exception is None:
|
||||
return 503
|
||||
|
||||
for original_status in (
|
||||
getattr(original_exception, "status_code", None),
|
||||
getattr(getattr(original_exception, "response", None), "status_code", None),
|
||||
):
|
||||
if original_status is None:
|
||||
continue
|
||||
try:
|
||||
return int(original_status)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
|
||||
return 503
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
|
|
@ -954,8 +972,8 @@ class MidStreamFallbackError(ServiceUnavailableError): # type: ignore
|
|||
generated_content: str = "",
|
||||
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
|
||||
original_status = self._get_status_code(original_exception)
|
||||
self.status_code = original_status
|
||||
self.message = f"litellm.MidStreamFallbackError: {message}"
|
||||
self.model = model
|
||||
self.llm_provider = llm_provider
|
||||
|
|
@ -997,7 +1015,7 @@ 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
|
||||
self.status_code = original_status
|
||||
self.response = _saved_response
|
||||
self.request = _saved_request
|
||||
self.message = _saved_message
|
||||
|
|
|
|||
|
|
@ -254,6 +254,51 @@ 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_handles_non_numeric_status_code(self):
|
||||
"""
|
||||
Custom/OpenAI-mapped exceptions can expose non-HTTP status codes like
|
||||
"litellm_error"; MidStreamFallbackError should still be constructible.
|
||||
"""
|
||||
|
||||
class NonNumericStatusError(Exception):
|
||||
status_code = "litellm_error"
|
||||
|
||||
midstream_error = MidStreamFallbackError(
|
||||
message="stream broke",
|
||||
model="gpt-4o-mini",
|
||||
llm_provider="openai",
|
||||
original_exception=NonNumericStatusError("rate limited"),
|
||||
)
|
||||
|
||||
assert midstream_error.status_code == 503
|
||||
assert midstream_error.response.status_code == 503
|
||||
|
||||
def test_midstream_fallback_error_uses_response_status_code_fallback(self):
|
||||
"""
|
||||
If exception.status_code is malformed but response.status_code is valid,
|
||||
preserve the underlying HTTP status.
|
||||
"""
|
||||
|
||||
class NonNumericStatusError(Exception):
|
||||
status_code = "litellm_error"
|
||||
|
||||
def __init__(self, response: httpx.Response):
|
||||
self.response = response
|
||||
|
||||
response = httpx.Response(
|
||||
status_code=429,
|
||||
request=httpx.Request("POST", "https://api.openai.com/v1/chat/completions"),
|
||||
)
|
||||
midstream_error = MidStreamFallbackError(
|
||||
message="stream broke",
|
||||
model="gpt-4o-mini",
|
||||
llm_provider="openai",
|
||||
original_exception=NonNumericStatusError(response=response),
|
||||
)
|
||||
|
||||
assert midstream_error.status_code == 429
|
||||
assert midstream_error.response.status_code == 429
|
||||
|
||||
|
||||
class TestProxyHeaderExtraction:
|
||||
"""Test that proxy correctly extracts headers from exceptions."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue