LiteLLMLiteLLM 1.101 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
20 small wins to finish your pathNext lesson

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.

Exampleflaky_llm.py
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()
Example
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

Example
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.

Try it yourself
  • Raise litellm.AuthenticationError from DownLLM and catch it.
  • Catch Exception instead and print type(error).__mro__[:3].
  • Call flaky/small three times in a row. Which call succeeds?

You understood something today that you didn't yesterday.