diff --git a/litellm/exceptions.py b/litellm/exceptions.py index ccf6e2d762..44a5e2dceb 100644 --- a/litellm/exceptions.py +++ b/litellm/exceptions.py @@ -5,6 +5,9 @@ from openai.error import ( RateLimitError, ServiceUnavailableError, OpenAIError, + APIError, + Timeout, + APIConnectionError, ) @@ -29,6 +32,16 @@ class InvalidRequestError(InvalidRequestError): # type: ignore self.message, f"{self.model}" ) # Call the base class constructor with the parameters it needs +class Timeout(Timeout): # type: ignore + def __init__(self, message, model, llm_provider): + self.status_code = 408 + self.message = message + self.model = model + self.llm_provider = llm_provider + super().__init__( + self.message, f"{self.model}" + ) # Call the base class constructor with the parameters it needs + # sub class of invalid request error - meant to give more granularity for error handling context window exceeded errors class ContextWindowExceededError(InvalidRequestError): # type: ignore def __init__(self, message, model, llm_provider): @@ -63,6 +76,25 @@ class ServiceUnavailableError(ServiceUnavailableError): # type: ignore ) # Call the base class constructor with the parameters it needs +class APIError(APIError): # raise this when the API returns an invalid response object - https://github.com/openai/openai-python/blob/1be14ee34a0f8e42d3f9aa5451aa4cb161f1781f/openai/api_requestor.py#L401 + def __init__(self, status_code, message, llm_provider, model): + self.status_code = status_code + self.message = message + self.llm_provider = llm_provider + self.model = model + super().__init__( + self.message + ) + +class APIConnectionError(APIConnectionError): # raised if an invalid request (not get, delete, put, post) is made + def __init__(self, message, llm_provider, model): + self.message = message + self.llm_provider = llm_provider + self.model = model + super().__init__( + self.message + ) + class OpenAIError(OpenAIError): # type: ignore def __init__(self, original_exception): self.status_code = original_exception.http_status @@ -73,4 +105,4 @@ class OpenAIError(OpenAIError): # type: ignore headers=original_exception.headers, code=original_exception.code, ) - self.llm_provider = "openai" + self.llm_provider = "openai" \ No newline at end of file diff --git a/litellm/utils.py b/litellm/utils.py index 9fa7b0d936..39be90337d 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -26,7 +26,10 @@ from .exceptions import ( RateLimitError, ServiceUnavailableError, OpenAIError, - ContextWindowExceededError + ContextWindowExceededError, + Timeout, + APIConnectionError, + APIError ) from typing import List, Dict, Union, Optional from .caching import Cache @@ -1495,6 +1498,13 @@ def exception_type(model, original_exception, custom_llm_provider): model=model, llm_provider="anthropic", ) + elif original_exception.status_code == 408: + exception_mapping_worked = True + raise Timeout( + message=f"AnthropicException - {original_exception.message}", + model=model, + llm_provider="anthropic" + ) elif original_exception.status_code == 413: exception_mapping_worked = True raise InvalidRequestError( @@ -1509,16 +1519,21 @@ def exception_type(model, original_exception, custom_llm_provider): llm_provider="anthropic", model=model ) - elif ( - "Could not resolve authentication method. Expected either api_key or auth_token to be set." - in error_str - ): - exception_mapping_worked = True - raise AuthenticationError( - message=f"AnthropicException - {original_exception.message}", - llm_provider="anthropic", - model=model - ) + elif original_exception.status_code == 500: + exception_mapping_worked = True + raise ServiceUnavailableError( + message=f"AnthropicException - {original_exception.message}", + llm_provider="anthropic", + model=model + ) + else: + exception_mapping_worked = True + raise APIError( + status_code=original_exception.status_code, + message=f"AnthropicException - {original_exception.message}", + llm_provider="anthropic", + model=model + ) elif "replicate" in model: if "Incorrect authentication token" in error_str: exception_mapping_worked = True @@ -1551,11 +1566,20 @@ def exception_type(model, original_exception, custom_llm_provider): elif ( exception_type == "ReplicateError" ): # ReplicateError implies an error on Replicate server side, not user side + exception_mapping_worked = True raise ServiceUnavailableError( message=f"ReplicateException - {error_str}", llm_provider="replicate", model=model ) + else: + exception_mapping_worked = True + raise APIError( + status_code=original_exception.status_code, + message=f"ReplicateException - {original_exception.message}", + llm_provider="replicate", + model=model + ) elif model in litellm.cohere_models: # Cohere if ( "invalid api token" in error_str @@ -1583,6 +1607,14 @@ def exception_type(model, original_exception, custom_llm_provider): llm_provider="cohere", model=model ) + else: + exception_mapping_worked = True + raise APIError( + status_code=original_exception.status_code, + message=f"CohereException - {original_exception.message}", + llm_provider="cohere", + model=model + ) elif custom_llm_provider == "huggingface": if "length limit exceeded" in error_str: exception_mapping_worked = True @@ -1606,6 +1638,13 @@ def exception_type(model, original_exception, custom_llm_provider): model=model, llm_provider="huggingface", ) + elif original_exception.status_code == 408: + exception_mapping_worked = True + raise Timeout( + message=f"HuggingfaceException - {original_exception.message}", + model=model, + llm_provider="huggingface" + ) elif original_exception.status_code == 429: exception_mapping_worked = True raise RateLimitError( @@ -1613,6 +1652,14 @@ def exception_type(model, original_exception, custom_llm_provider): llm_provider="huggingface", model=model ) + else: + exception_mapping_worked = True + raise APIError( + status_code=original_exception.status_code, + message=f"HuggingfaceException - {original_exception.message}", + llm_provider="huggingface", + model=model + ) elif custom_llm_provider == "ai21": if hasattr(original_exception, "message"): if "Prompt has too many tokens" in original_exception.message: @@ -1630,6 +1677,13 @@ def exception_type(model, original_exception, custom_llm_provider): llm_provider="ai21", model=model ) + elif original_exception.status_code == 408: + exception_mapping_worked = True + raise Timeout( + message=f"AI21Exception - {original_exception.message}", + model=model, + llm_provider="ai21" + ) if original_exception.status_code == 422: exception_mapping_worked = True raise InvalidRequestError( @@ -1643,6 +1697,14 @@ def exception_type(model, original_exception, custom_llm_provider): message=f"AI21Exception - {original_exception.message}", llm_provider="ai21", ) + else: + exception_mapping_worked = True + raise APIError( + status_code=original_exception.status_code, + message=f"AI21Exception - {original_exception.message}", + llm_provider="ai21", + model=model + ) elif custom_llm_provider == "together_ai": error_response = json.loads(error_str) if "error" in error_response and "`inputs` tokens + `max_new_tokens` must be <=" in error_response["error"]: @@ -1673,6 +1735,13 @@ def exception_type(model, original_exception, custom_llm_provider): model=model, llm_provider="together_ai" ) + elif original_exception.status_code == 408: + exception_mapping_worked = True + raise Timeout( + message=f"TogetherAIException - {original_exception.message}", + model=model, + llm_provider="together_ai" + ) elif original_exception.status_code == 429: exception_mapping_worked = True raise RateLimitError( @@ -1680,7 +1749,14 @@ def exception_type(model, original_exception, custom_llm_provider): llm_provider="together_ai", model=model ) - raise original_exception # base case - return the original exception + else: + exception_mapping_worked = True + raise APIError( + status_code=original_exception.status_code, + message=f"TogetherAIException - {original_exception.message}", + llm_provider="together_ai", + model=model + ) else: raise original_exception except Exception as e: