math-solver / llm /errors.py
Cuong2004
Deploy API from GitHub Actions
0772b5a
Raw
History Blame Contribute Delete
2.88 kB
import re
import logging
from enum import Enum
from typing import Optional
logger = logging.getLogger(__name__)
class ErrorCategory(str, Enum):
RATE_LIMIT = "RATE_LIMIT"
QUOTA_EXHAUSTED = "QUOTA_EXHAUSTED"
AUTH_ERROR = "AUTH_ERROR"
INVALID_REQUEST = "INVALID_REQUEST"
TIMEOUT = "TIMEOUT"
NETWORK = "NETWORK"
SERVER_ERROR = "SERVER_ERROR"
UNKNOWN = "UNKNOWN"
class ErrorClassifier:
"""Classifies exceptions from LiteLLM and HTTP client into structured ErrorCategory."""
@staticmethod
def classify(exc: Exception) -> ErrorCategory:
err_msg = str(exc).lower()
err_type = type(exc).__name__.lower()
# 1. Authentication / Permission errors (Disable key)
if any(w in err_msg for w in ["invalid_api_key", "invalid api key", "unauthorized", "authentication", "api_key_invalid", "permission_denied"]) or "auth" in err_type:
return ErrorCategory.AUTH_ERROR
# 2. Permanent Quota Exhaustion
if any(w in err_msg for w in ["daily quota", "quota exceeded", "billing", "credit", "insufficient_quota"]):
return ErrorCategory.QUOTA_EXHAUSTED
# 3. Rate Limit / Resource Exhausted (Temporary Cooldown)
if any(w in err_msg for w in ["rate limit", "ratelimit", "429", "resource_exhausted", "too many requests"]) or "ratelimit" in err_type:
return ErrorCategory.RATE_LIMIT
# 4. Timeout errors
if any(w in err_msg for w in ["timeout", "timed out", "deadline_exceeded"]) or "timeout" in err_type:
return ErrorCategory.TIMEOUT
# 5. Network / Connection errors
if any(w in err_msg for w in ["connection error", "connection reset", "broken pipe", "connect_error", "remotedisconnected"]):
return ErrorCategory.NETWORK
# 6. Server errors (500, 502, 503, 504)
if any(w in err_msg for w in ["500", "502", "503", "504", "internal server error", "bad gateway", "service unavailable", "overloaded"]):
return ErrorCategory.SERVER_ERROR
# 7. Invalid Request (e.g. context length exceeded, bad params - do not key-retry)
if any(w in err_msg for w in ["context_length_exceeded", "maximum context length", "invalid_request_error", "bad request", "400"]):
return ErrorCategory.INVALID_REQUEST
return ErrorCategory.UNKNOWN
@staticmethod
def extract_retry_after(exc: Exception) -> Optional[int]:
"""Attempts to extract Retry-After duration from exception message or headers."""
err_msg = str(exc)
# Check for patterns like "retry after 45s" or "Retry-After: 30"
match = re.search(r"(?:retry[-_ ]after|retry in)\s*:?\s*(\d+)", err_msg, re.IGNORECASE)
if match:
try:
return int(match.group(1))
except ValueError:
pass
return None