python-backoff
raw JSON → 2.3.1 verified Tue May 12 auth: no python install: verified quickstart: verified
python-backoff is a Python library providing function decorators for configurable backoff and retry strategies. It allows you to wrap functions to automatically retry their execution until a specified condition is met, such as handling transient failures from unreliable network resources or external APIs. The library supports both synchronous and asynchronous (asyncio) code, offering various wait generators like exponential, fibonacci, and constant backoff. It is actively maintained, with recent releases in late 2025, and the current version is 2.3.1.
pip install backoff Common errors
error ModuleNotFoundError: No module named 'backoff' ↓
cause The 'backoff' library is not installed in the Python environment, or there is an issue with the Python path.
fix
Install the library using pip:
pip install backoff. If using Python 3.7 and encountering 'importlib.metadata' issues with backoff v2.1.1, consider upgrading Python or installing an older, compatible version of backoff (e.g., pip install backoff==2.1.0). error TypeError: catching classes that do not inherit from BaseException is not allowed ↓
cause The `backoff` decorator's `exception` parameter was provided with an object that is not a proper Python exception class, such as an instance of an exception or a non-exception type.
fix
Ensure that only actual exception classes (e.g.,
ValueError, requests.exceptions.RequestException, Exception) are passed to the exception parameter of @backoff.on_exception. error @backoff.on_exception(max_tries=5) def my_function(): pass ↓
cause The `@backoff.on_exception` decorator requires at least a `wait_gen` (a wait generator like `backoff.expo` or `backoff.constant`) and an `exception` type to be specified to define the retry strategy and which errors to catch. Omitting these will result in the decorator not functioning as intended or retrying on all exceptions without a specific backoff strategy.
fix
Provide a wait generator (e.g.,
backoff.expo) and the specific exception type(s) to retry on. For example: @backoff.on_exception(backoff.expo, ValueError, max_tries=5). Warnings
breaking Python 3.7 support was dropped in `backoff` version 2.3.0. Users on Python 3.7 attempting to upgrade to 2.3.0 or later will encounter compatibility issues. ↓
fix Upgrade your Python environment to 3.8 or newer before upgrading `backoff`.
breaking In `backoff` v2.3.1, the `target` key in the `details` dictionary passed to event handlers (like `on_backoff`, `on_giveup`) changed its type from a string representation to an actual function reference. ↓
fix If your event handlers inspect `details['target']` and expect a string, update your logic to handle a function object instead. For example, use `details['target'].__name__` to get the function name.
gotcha The `@backoff.on_exception` decorator requires the decorated function to raise the specified exception (or a subclass) to trigger a retry. If the function catches the exception internally with a bare `except:` clause and does not re-raise it, `backoff` will not detect the failure and will not retry. ↓
fix Ensure that the exceptions you want `backoff` to handle are propagated out of the decorated function. Avoid broad `except:` clauses, or explicitly `raise` the exception after handling it internally if retries are still desired.
gotcha When using `@backoff.on_exception`, it is crucial to provide both a wait generator (e.g., `backoff.expo`, `backoff.constant`) and at least one exception type to retry on. Failing to provide these parameters makes the decorator ineffective. ↓
fix Always specify the wait strategy and the exceptions. Example: `@backoff.on_exception(backoff.expo, SomeError, max_tries=5)`.
Install compatibility verified last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) - - - -
3.10 alpine (musl) - - 0.10s 17.9M
3.10 slim (glibc) - - - -
3.10 slim (glibc) - - 0.07s 18M
3.11 alpine (musl) - - - -
3.11 alpine (musl) - - 0.19s 19.7M
3.11 slim (glibc) - - - -
3.11 slim (glibc) - - 0.14s 20M
3.12 alpine (musl) - - - -
3.12 alpine (musl) - - 0.41s 11.6M
3.12 slim (glibc) - - - -
3.12 slim (glibc) - - 0.34s 12M
3.13 alpine (musl) - - - -
3.13 alpine (musl) - - 0.39s 11.2M
3.13 slim (glibc) - - - -
3.13 slim (glibc) - - 0.36s 12M
3.9 alpine (musl) - - - -
3.9 alpine (musl) - - 0.09s 17.4M
3.9 slim (glibc) - - - -
3.9 slim (glibc) - - 0.08s 18M
Imports
- on_exception wrong
import backoffcorrectfrom backoff import on_exception, expo, full_jitter, fatal_exception - on_predicate
from backoff import on_predicate, fibo
Quickstart verified last tested: 2026-04-23
import backoff
import random
import time
# Simulate a flaky external API call
CALL_COUNT = 0
MAX_FAILURES = 3
@backoff.on_exception(backoff.expo, # Exponential backoff strategy
(ValueError, IOError), # Retry on these exceptions
max_tries=5, # Max attempts
max_time=30, # Max total time in seconds
jitter=backoff.full_jitter, # Add randomness to delays
on_backoff=lambda details: print(f"Backing off {details['wait']:.2f}s for {details['target'].__name__} after {details['tries']} tries, due to {details['exception'].__class__.__name__}"),
on_giveup=lambda details: print(f"Giving up on {details['target'].__name__} after {details['tries']} tries, last exception {details['exception'].__class__.__name__}"))
def call_flaky_api():
global CALL_COUNT
CALL_COUNT += 1
print(f"Attempt {CALL_COUNT}: Calling flaky API...")
if CALL_COUNT <= MAX_FAILURES:
if random.random() < 0.8: # 80% chance to raise ValueError initially
raise ValueError("API returned invalid data")
else:
raise IOError("Network connection lost") # Simulate another failure
print(f"Attempt {CALL_COUNT}: API call successful!")
return "Data from API"
try:
result = call_flaky_api()
print(f"Final result: {result}")
except (ValueError, IOError) as e:
print(f"Operation failed after multiple retries: {e}")
# Reset call count for a new demonstration
CALL_COUNT = 0
print("\n--- Demonstrating with higher success chance after initial failures ---")
MAX_FAILURES = 1 # Will likely succeed on the 2nd attempt
try:
result = call_flaky_api()
print(f"Final result: {result}")
except (ValueError, IOError) as e:
print(f"Operation failed after multiple retries: {e}")