mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
fix(proxy): ProxyException.__str__() returns empty string
ProxyException never called super().__init__(message), causing str(e) to return '' in all exception logging throughout the proxy. HTTP responses were unaffected (they use to_dict()), but every log line that stringified the exception produced blank error messages. Adds super().__init__() call and __str__ method. Fixes #22644
This commit is contained in:
parent
92407ec0d4
commit
bdb0a78ce9
2 changed files with 118 additions and 0 deletions
|
|
@ -3208,6 +3208,7 @@ class ProxyException(Exception):
|
|||
provider_specific_fields: Optional[dict] = None,
|
||||
):
|
||||
self.message = str(message)
|
||||
super().__init__(self.message)
|
||||
self.type = type
|
||||
self.param = param
|
||||
self.openai_code = openai_code or code
|
||||
|
|
@ -3232,6 +3233,9 @@ class ProxyException(Exception):
|
|||
elif RouterErrors.no_deployments_with_tag_routing.value in self.message:
|
||||
self.code = "401"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.message
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Converts the ProxyException instance to a dictionary."""
|
||||
error_dict: Dict[str, Optional[Union[str, Dict]]] = {
|
||||
|
|
|
|||
114
tests/test_litellm/proxy/test_proxy_exception_str.py
Normal file
114
tests/test_litellm/proxy/test_proxy_exception_str.py
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
"""
|
||||
Tests for ProxyException string representation.
|
||||
|
||||
Verifies that str(ProxyException(...)) returns the exception message
|
||||
instead of an empty string. See https://github.com/BerriAI/litellm/issues/22644
|
||||
"""
|
||||
|
||||
from litellm.proxy._types import ProxyException
|
||||
|
||||
|
||||
class TestProxyExceptionStr:
|
||||
"""Tests for ProxyException.__str__() behavior."""
|
||||
|
||||
def test_proxy_exception_str_returns_message(self):
|
||||
"""str(ProxyException(...)) should return the message, not empty string."""
|
||||
exc = ProxyException(
|
||||
message="auth failed",
|
||||
type="bad_request_error",
|
||||
param="key_alias",
|
||||
code=400,
|
||||
)
|
||||
assert str(exc) == "auth failed"
|
||||
|
||||
def test_proxy_exception_str_empty_message(self):
|
||||
"""str() should work correctly with an empty message."""
|
||||
exc = ProxyException(
|
||||
message="",
|
||||
type="bad_request_error",
|
||||
param="key_alias",
|
||||
code=400,
|
||||
)
|
||||
assert str(exc) == ""
|
||||
|
||||
def test_proxy_exception_str_unicode(self):
|
||||
"""str() should handle unicode messages correctly."""
|
||||
msg = "Error: \u2018invalid key\u2019 \u2014 please retry \U0001f512"
|
||||
exc = ProxyException(
|
||||
message=msg,
|
||||
type="bad_request_error",
|
||||
param="key_alias",
|
||||
code=400,
|
||||
)
|
||||
assert str(exc) == msg
|
||||
|
||||
def test_proxy_exception_repr(self):
|
||||
"""repr() should include the message text."""
|
||||
exc = ProxyException(
|
||||
message="something broke",
|
||||
type="internal_error",
|
||||
param=None,
|
||||
code=500,
|
||||
)
|
||||
assert "something broke" in repr(exc)
|
||||
|
||||
def test_proxy_exception_to_dict_unchanged(self):
|
||||
"""to_dict() output format must remain exactly the same after the fix."""
|
||||
exc = ProxyException(
|
||||
message="model not found",
|
||||
type="invalid_request_error",
|
||||
param="model",
|
||||
code=404,
|
||||
)
|
||||
result = exc.to_dict()
|
||||
assert result == {
|
||||
"message": "model not found",
|
||||
"type": "invalid_request_error",
|
||||
"param": "model",
|
||||
"code": "404",
|
||||
}
|
||||
|
||||
def test_proxy_exception_to_dict_with_provider_fields(self):
|
||||
"""to_dict() should include provider_specific_fields when present."""
|
||||
exc = ProxyException(
|
||||
message="rate limited",
|
||||
type="rate_limit_error",
|
||||
param=None,
|
||||
code=429,
|
||||
provider_specific_fields={"retry_after": 30},
|
||||
)
|
||||
result = exc.to_dict()
|
||||
assert result["provider_specific_fields"] == {"retry_after": 30}
|
||||
assert result["message"] == "rate limited"
|
||||
|
||||
def test_proxy_exception_chaining(self):
|
||||
"""raise ProxyException from ValueError should preserve __cause__."""
|
||||
inner = ValueError("inner error")
|
||||
try:
|
||||
try:
|
||||
raise inner
|
||||
except ValueError:
|
||||
raise ProxyException(
|
||||
message="outer error",
|
||||
type="bad_request_error",
|
||||
param="test",
|
||||
code=400,
|
||||
) from inner
|
||||
except ProxyException as exc:
|
||||
assert str(exc) == "outer error"
|
||||
assert exc.__cause__ is inner
|
||||
|
||||
def test_proxy_exception_catch_and_stringify(self):
|
||||
"""Simulates the real-world pattern: try/except that formats str(e) into a log."""
|
||||
log_output = ""
|
||||
try:
|
||||
raise ProxyException(
|
||||
message="key expired",
|
||||
type="authentication_error",
|
||||
param="api_key",
|
||||
code=401,
|
||||
)
|
||||
except ProxyException as exc:
|
||||
log_output = "Error - {}".format(str(exc))
|
||||
|
||||
assert log_output == "Error - key expired"
|
||||
Loading…
Add table
Reference in a new issue