From c918e18852b0455373abaa77e8cc01ffab2b22ec Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 19 Sep 2025 16:32:13 -0700 Subject: [PATCH] Enrich rate limit error message with specific limit type and reset time (#14736) - Add specific rate limit type (requests/tokens/max_parallel_requests) to error message - Include current limit value for better context - Display reset time in human-readable format - Handle negative remaining values gracefully by showing 0 instead - Add reset_at header with timestamp for programmatic use Fixes issue where rate limit errors were ambiguous about which type of limit was exceeded and when the limit would reset. Co-authored-by: Cursor Agent --- .../hooks/parallel_request_limiter_v3.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/hooks/parallel_request_limiter_v3.py b/litellm/proxy/hooks/parallel_request_limiter_v3.py index 87f4236b5aa..8ef0a662ffe 100644 --- a/litellm/proxy/hooks/parallel_request_limiter_v3.py +++ b/litellm/proxy/hooks/parallel_request_limiter_v3.py @@ -565,13 +565,34 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): for i, status in enumerate(response["statuses"]): if status["code"] == "OVER_LIMIT": descriptor = descriptors[floor(i / 2)] + + # Calculate reset time (window_start + window_size) + now = datetime.now().timestamp() + reset_time = now + self.window_size # Conservative estimate + reset_time_formatted = datetime.fromtimestamp(reset_time).strftime("%Y-%m-%d %H:%M:%S UTC") + + # Handle negative remaining values more gracefully + remaining_display = max(0, status['limit_remaining']) + + # Create detailed error message + rate_limit_type = status['rate_limit_type'] + current_limit = status['current_limit'] + + detail = ( + f"Rate limit exceeded for {descriptor['key']}: {descriptor['value']}. " + f"Limit type: {rate_limit_type}. " + f"Current limit: {current_limit}, Remaining: {remaining_display}. " + f"Limit resets at: {reset_time_formatted}" + ) + raise HTTPException( status_code=429, - detail=f"Rate limit exceeded for {descriptor['key']}: {descriptor['value']}. Remaining: {status['limit_remaining']}", + detail=detail, headers={ "retry-after": str(self.window_size), "rate_limit_type": str(status["rate_limit_type"]), - }, # Retry after 1 minute + "reset_at": reset_time_formatted, + }, ) else: