From af811ec81e172fd81bc7d61d3f15a005af791220 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 03:36:16 +0000 Subject: [PATCH] fix(proxy): set num_retries/max_retries on ProxyHTTPRateLimitError ProxyHTTPRateLimitError inherits from RateLimitError but did not call RateLimitError.__init__, so num_retries/max_retries were never set. When Starlette's HTTPException lacks __str__, MRO falls through to RateLimitError.__str__, which unconditionally reads these attributes and raises AttributeError during logging/traceback formatting. Initialize them to None defensively. --- litellm/proxy/hooks/rate_limiter_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/litellm/proxy/hooks/rate_limiter_utils.py b/litellm/proxy/hooks/rate_limiter_utils.py index b64a2110f62..df81abd4361 100644 --- a/litellm/proxy/hooks/rate_limiter_utils.py +++ b/litellm/proxy/hooks/rate_limiter_utils.py @@ -94,6 +94,12 @@ class ProxyHTTPRateLimitError(HTTPException, RateLimitError): # `message` is what RateLimitError.__str__ would print and what some # observability callbacks log. Keep it human-readable. self.message = detail if isinstance(detail, str) else str(detail) + # `RateLimitError.__str__` (resolved via MRO since Starlette's + # HTTPException doesn't define `__str__`) unconditionally reads + # these attributes. Set them so `str(exc)` doesn't raise + # AttributeError from logging/traceback paths. + self.num_retries: Optional[int] = None + self.max_retries: Optional[int] = None def convert_priority_to_percent(