{"id":383,"library":"backoff","title":"python-backoff","description":"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.","status":"active","version":"2.3.1","language":"python","source_language":"en","source_url":"https://github.com/python-backoff/backoff","tags":["retry","backoff","decorator","resilience","async","asyncio"],"install":[{"cmd":"pip install backoff","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"While `import backoff` is correct, direct import of specific decorators and wait generators is idiomatic for clearer usage.","wrong":"import backoff","symbol":"on_exception","correct":"from backoff import on_exception, expo, full_jitter, fatal_exception"},{"note":"Used for retrying based on the return value of a function.","symbol":"on_predicate","correct":"from backoff import on_predicate, fibo"}],"quickstart":{"code":"import backoff\nimport random\nimport time\n\n# Simulate a flaky external API call\nCALL_COUNT = 0\nMAX_FAILURES = 3\n\n@backoff.on_exception(backoff.expo,  # Exponential backoff strategy\n                      (ValueError, IOError), # Retry on these exceptions\n                      max_tries=5,         # Max attempts\n                      max_time=30,         # Max total time in seconds\n                      jitter=backoff.full_jitter, # Add randomness to delays\n                      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__}\"),\n                      on_giveup=lambda details: print(f\"Giving up on {details['target'].__name__} after {details['tries']} tries, last exception {details['exception'].__class__.__name__}\"))\ndef call_flaky_api():\n    global CALL_COUNT\n    CALL_COUNT += 1\n    print(f\"Attempt {CALL_COUNT}: Calling flaky API...\")\n    if CALL_COUNT <= MAX_FAILURES:\n        if random.random() < 0.8: # 80% chance to raise ValueError initially\n            raise ValueError(\"API returned invalid data\")\n        else:\n            raise IOError(\"Network connection lost\") # Simulate another failure\n    print(f\"Attempt {CALL_COUNT}: API call successful!\")\n    return \"Data from API\"\n\n\ntry:\n    result = call_flaky_api()\n    print(f\"Final result: {result}\")\nexcept (ValueError, IOError) as e:\n    print(f\"Operation failed after multiple retries: {e}\")\n\n# Reset call count for a new demonstration\nCALL_COUNT = 0\nprint(\"\\n--- Demonstrating with higher success chance after initial failures ---\")\nMAX_FAILURES = 1 # Will likely succeed on the 2nd attempt\ntry:\n    result = call_flaky_api()\n    print(f\"Final result: {result}\")\nexcept (ValueError, IOError) as e:\n    print(f\"Operation failed after multiple retries: {e}\")","lang":"python","description":"This quickstart demonstrates how to use the `@backoff.on_exception` decorator to automatically retry a function that might fail intermittently. It configures exponential backoff with jitter, sets a maximum number of tries and total elapsed time, and includes `on_backoff` and `on_giveup` handlers for logging retry attempts. The example simulates a flaky API that raises exceptions for the first few calls, eventually succeeding or giving up."},"warnings":[{"fix":"Upgrade your Python environment to 3.8 or newer before upgrading `backoff`.","message":"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.","severity":"breaking","affected_versions":">=2.3.0"},{"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.","message":"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.","severity":"breaking","affected_versions":"2.3.1"},{"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.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Always specify the wait strategy and the exceptions. Example: `@backoff.on_exception(backoff.expo, SomeError, max_tries=5)`.","message":"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.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T13:26:37.915Z","next_check":"2026-07-08T00:00:00.000Z","problems":[{"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`).","cause":"The 'backoff' library is not installed in the Python environment, or there is an issue with the Python path.","error":"ModuleNotFoundError: No module named 'backoff'"},{"fix":"Ensure that only actual exception classes (e.g., `ValueError`, `requests.exceptions.RequestException`, `Exception`) are passed to the `exception` parameter of `@backoff.on_exception`.","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.","error":"TypeError: catching classes that do not inherit from BaseException is not allowed"},{"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)`.","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.","error":"@backoff.on_exception(max_tries=5)\ndef my_function():\n    pass"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":4.3,"disk_size":"17.9M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":4.3,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.19,"mem_mb":5.3,"disk_size":"19.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":5.3,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.41,"mem_mb":8.2,"disk_size":"11.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.34,"mem_mb":8.2,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.39,"mem_mb":8.7,"disk_size":"11.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.36,"mem_mb":8.7,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":4.2,"disk_size":"17.4M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":4.2,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}