Errors: one set of exceptions for every provider
Providers fail in their own words. LiteLLM maps their errors to one set of exception types, the OpenAI SDK's, so a rate limit is a RateLimitError whoever sent it.
Two more stand-in providers: one that is rate-limited for its first two calls, and one that is having an outage.
import litellm
from litellm import CustomLLM
from litellm.utils import custom_llm_setup
from shop_llm import shop
class FlakyLLM(CustomLLM):
"""Fails the first `failures` calls with a rate limit, then answers like ShopLLM."""
def __init__(self, failures):
super().__init__()
self.failures = failures
self.calls = 0
def completion(self, model, messages, *args, **kwargs):
self.calls += 1
if self.calls <= self.failures:
raise litellm.RateLimitError(message="slow down", llm_provider="flaky", model=model)
return shop.completion(model, messages)
async def acompletion(self, model, messages, *args, **kwargs):
return self.completion(model, messages)
class DownLLM(CustomLLM):
"""A provider that is having an outage."""
def completion(self, model, messages, *args, **kwargs):
raise litellm.ServiceUnavailableError(message="provider is down", llm_provider="down", model=model)
async def acompletion(self, model, messages, *args, **kwargs):
return self.completion(model, messages)
flaky = FlakyLLM(failures=2)
down = DownLLM()
litellm.custom_provider_map = [
{"provider": "shop", "custom_handler": shop},
{"provider": "flaky", "custom_handler": flaky},
{"provider": "down", "custom_handler": down},
]
custom_llm_setup()import litellm
from litellm import completion
import flaky_llm
litellm.suppress_debug_info = True
for model in ["flaky/small", "down/large"]:
try:
completion(model=model, messages=[{"role": "user", "content": "I was charged twice for one order"}])
except litellm.RateLimitError as error:
print("rate limited:", error.status_code, error.llm_provider)
except litellm.ServiceUnavailableError as error:
print("unavailable:", error.status_code, error.llm_provider)Each exception carries the HTTP status_code, the llm_provider that failed and a message. The exception mapping page lists the types: 400 BadRequestError, 401 AuthenticationError, 404 NotFoundError, 408 Timeout, 429 RateLimitError, 503 ServiceUnavailableError and more.
Existing OpenAI error handling still works
import openai
try:
completion(model="down/large", messages=[{"role": "user", "content": "I was charged twice for one order"}])
except openai.APIStatusError as error:
print(type(error).__name__, isinstance(error, litellm.ServiceUnavailableError))Every LiteLLM exception inherits from the matching exception in the openai package, so an app that already catches OpenAI's errors catches every provider's through LiteLLM.
Which errors are worth retrying
From APIs for AI: a 429 or a 5xx may work on a second try; a 400 or 401 will fail the same way again. The next part of the course acts on exactly that difference.
- Raise
litellm.AuthenticationErrorfromDownLLMand catch it. - Catch
Exceptioninstead and printtype(error).__mro__[:3]. - Call
flaky/smallthree times in a row. Which call succeeds?
You understood something today that you didn't yesterday.