Skip to main content

llm-retry-py

PyPI Python License: MIT

Exponential backoff with full jitter for LLM API calls.

Most retry libraries are framework middleware or async-only. This one is a small function you wrap around any callable. Sync and async loops share the same RetryPolicy. Built-in retryable-code sets for Anthropic, OpenAI, AWS Bedrock, and Google Gemini ship in llm_retry.predicates.

Sibling to the Rust crate llm-retry.

Install

pip install llm-retry-py

Use

Sync:

from llm_retry import retry, RetryPolicy, predicates

def call_anthropic():
    return client.messages.create(model="claude-sonnet-4-5", ...)

resp = retry(
    call_anthropic,
    policy=RetryPolicy(),
    should_retry=lambda e: predicates.is_anthropic_retryable(str(e)),
)

Async (works with any asyncio code, no runtime lock-in beyond asyncio.sleep):

from llm_retry import retry_async, RetryPolicy, predicates

async def call_openai():
    return await client.chat.completions.create(...)

resp = await retry_async(
    call_openai,
    policy=RetryPolicy(),
    should_retry=lambda e: predicates.is_openai_retryable(str(e)),
)

Custom predicate (BYO matcher):

import httpx

def should_retry(e: Exception) -> bool:
    if isinstance(e, httpx.TimeoutException):
        return True
    if isinstance(e, httpx.HTTPStatusError):
        return predicates.is_http_status_retryable(e.response.status_code)
    return False

resp = retry(call, policy=RetryPolicy(), should_retry=should_retry)

RetryPolicy

Defaults: 6 attempts, 500ms base delay, 30s cap, full jitter.

from llm_retry import RetryPolicy, Jitter

policy = RetryPolicy(
    max_attempts=8,
    base_delay_ms=250,
    max_delay_ms=60_000,
    jitter=Jitter.FULL,  # FULL (default, AWS-recommended), EQUAL, or NONE
)

Backoff for attempt i (0-indexed) is min(base * 2**i, max), then jittered.

Jitter Resulting delay
NONE capped
EQUAL capped/2 + uniform(0, capped/2)
FULL uniform(0, capped) (recommended)

Presets

from llm_retry import predicates

predicates.is_anthropic_retryable("rate_limit_error")     # True
predicates.is_openai_retryable("server_error")            # True
predicates.is_bedrock_retryable("ThrottlingException")    # True
predicates.is_gemini_retryable("RESOURCE_EXHAUSTED")      # True
predicates.is_http_status_retryable(503)                  # True

The underlying lists are public constants you can extend:

from llm_retry.predicates import ANTHROPIC_RETRYABLE, contains_any

my_codes = ANTHROPIC_RETRYABLE + ("my_custom_transient_code",)
should_retry = lambda e: contains_any(str(e), my_codes)

Error type

A retry that does not succeed raises RetryExhausted:

from llm_retry import RetryExhausted

try:
    resp = retry(call, policy=RetryPolicy(), should_retry=lambda e: True)
except RetryExhausted as exc:
    exc.attempts        # how many tries ran
    exc.last_error      # the final exception raised by `call`

If the predicate returns False for the first error, that error is re-raised unchanged (no wrapping).

What it does NOT do

  • No HTTP client. Wrap any callable that raises.
  • No circuit breaker. Layer one on top if you want.
  • No deadline (stop after N seconds total). Combine with your own asyncio.wait_for or signal.alarm.
  • No structured logging hooks. Add them in your callable.

License

MIT

Metadata

Release files for llm-retry-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-retry-py 0.1.0
File Size Uploaded Provenance
llm_retry_py-0.1.0.tar.gz 8.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for llm-retry-py 0.1.0
File Interpreter ABI Platform
llm_retry_py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 16.8 kB

Release files / llm_retry_py-0.1.0.tar.gz

Download URL llm_retry_py-0.1.0.tar.gz
Size 8.9 kB
Tags Source
SHA-256 checksum
How to use checksums
54f2549812a73ba28b3248f775399721d02e5c01fb7649bbea64121fcc1ba7ca
BLAKE2b-256 checksum
How to use checksums
e8d080ddd01a6e4946612470c03ebf08584ae8529a74e9ca3dfbebec4daa6593
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release files / llm_retry_py-0.1.0-py3-none-any.whl

Download URL llm_retry_py-0.1.0-py3-none-any.whl
Size 7.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
20859fdbce5ad9057cc4bca56fe828cdb8650d4710a932ed86d81985c718fa5a
BLAKE2b-256 checksum
How to use checksums
dae88ca34f9ef423861818a33c29e49570bbd7363804313cf4983f66937dac44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Security for llm-retry-py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page