Skip to main content

LiteLLM Brownout

Move a LiteLLM team's chosen routes to cheaper models on budget tiers

No budget runaway, no quick drain of a team budget. Give a route a fallback and a percentage, and the gateway switches that route once the team's spend passes it.

PyPI version LiteLLM 1.101.6 to 1.106 License

Team-a's weekly budget fills toward $500. The gateway log announces the 75% and 90% tiers, then chat-qa switches to its fallback with x-brownout headers while code-review keeps its primary.

Example

Take a team with $500 a week. Its Q&A route falls back to a smaller model at 90%, and its code review route has no fallback.

Team spend Q&A route Code review route Signal
Below $375 Primary Primary
$375 to $449.99 Primary Primary 75% warning
$450 and above Fallback Primary 90% warning and downgrade headers
Too little left for the next request Refused Refused LiteLLM's 429

LiteLLM already reserves each request's cost, counts team spend across replicas and refuses requests past the budget. Brownout adds five things.

  • Warnings at any percentage: each team and route sets its own tiers, logged once per budget window across replicas. LiteLLM's own budget alerts fire at 85% and 95%.
  • Downgrades on the team's total: a route switches to its fallback at the percentage you set. LiteLLM's budget fallbacks switch only when a key exhausts a per-model budget.
  • Coding agents included: chat, text completion, Anthropic's /v1/messages, OpenAI's /v1/responses and Google's generateContent all downgrade, so a Claude Code or Codex session carries on with the fallback mid-task.
  • Checked fallbacks: brownout switches only to a fallback the gateway serves and prices, and that the caller's key and team may call.
  • Disclosure: x-brownout-* headers and the spend logs name the model that answered and why.

How it works

A request passes LiteLLM's authentication and budget reservation. Brownout reads the team's spend from Redis, finds it past the route's tier and serves the fallback. The response returns with x-brownout headers. The manifest brownout.yaml sets the policy.

One manifest, brownout.yaml, holds every team's budget, tiers and fallbacks. It lives in your repo next to the gateway config, so a policy change goes through code review, and brownout check runs it in CI. LiteLLM keeps enforcing the budget, and brownout picks the model that serves each request.

Requirements

Brownout governs every model call on the gateway, so the gateway needs a few things in place. init checks each one and prints the fix.

  • Every key that calls a model belongs to a team, and that team is in the manifest.
  • Budgets sit on teams, never on keys.
  • Clients use LiteLLM's unified routes. Provider pass-through routes, realtime, batches, fine-tuning and search tools are refused.
  • fail_closed_budget_enforcement is on, and coordination_redis points at a Redis.
  • LiteLLM is 1.101.6 to 1.106, pinned by image tag.

A gateway without Redis needs one that shares its REDIS_PASSWORD, such as this service.

services:
  redis:
    image: redis:7
    command: ["sh", "-c", "exec redis-server --requirepass \"$$REDIS_PASSWORD\" --appendonly yes --maxmemory-policy noeviction"]
    env_file:
      - .env

Get started

1. Run init against your gateway. Paste the master key on the first line.

read -rs LITELLM_MASTER_KEY && typeset +x LITELLM_MASTER_KEY
BROWNOUT_INIT_KEY=$(curl -sSf http://localhost:4000/user/new \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" \
  -d '{"user_id": "brownout-init", "user_role": "proxy_admin_viewer"}' | jq -er .key) \
  && export BROWNOUT_INIT_KEY
uvx --from litellm-brownout brownout init --gateway http://localhost:4000 --gateway-config config.yaml

2. Fix what it lists, rerun it with --write, then check the files.

uvx --from litellm-brownout brownout check --gateway-config brownout.config.yaml --manifest brownout.yaml
curl -sSf http://localhost:4000/user/delete \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" \
  -d '{"user_ids": ["brownout-init"]}'

3. Build the gateway image with brownout and run it on the new files.

FROM docker.litellm.ai/berriai/litellm:v1.106.1
RUN python -m ensurepip --upgrade && python -m pip install --no-deps litellm-brownout==0.1.0
services:
  litellm:
    build: .
    command: ["--config", "/app/brownout.config.yaml", "--port", "4000"]
    environment:
      BROWNOUT_MANIFEST: /app/brownout.yaml
    volumes:
      - ./brownout.config.yaml:/app/brownout.config.yaml:ro
      - ./brownout.yaml:/app/brownout.yaml:ro

4. Send one request with a team's key.

curl -s -i http://localhost:4000/v1/chat/completions \
  -H "Authorization: Bearer {team key}" -H "Content-Type: application/json" \
  -d '{"model": "{model}", "messages": [{"role": "user", "content": "hi"}], "max_tokens": 20}' \
  | grep -io '^x-brownout-[a-z-]*: [^[:cntrl:]]*\|"reason": *"[a-z_]*"'

What happened:

  • init read the gateway as a read-only brownout-init user and listed every request brownout would refuse, with the fix for each. OpenRouter models need a price, which one command prints.
  • --write created brownout.yaml, the manifest, and brownout.config.yaml, your config with brownout's settings. check validated both, and the brownout-init user was deleted.
  • The response names the model that answered in x-brownout-route-served. A refused request prints its reason instead. The master key belongs to no team, so brownout refuses it.

Your first fallback

Add a route under your team in brownout.yaml. Fill in each {placeholder}.

teams:
  "{team}":
    routes:
      "{route}":
        fallback: "{fallback}"
        degrade_at: 90

Add {fallback} to the team's model list in LiteLLM, run brownout check again and restart the gateway. For models added in the admin UI, check reads the gateway with a viewer key.

BROWNOUT_INIT_KEY=$(curl -sSf http://localhost:4000/user/new \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" \
  -d '{"user_id": "brownout-init", "user_role": "proxy_admin_viewer"}' | jq -er .key) \
  && export BROWNOUT_INIT_KEY
uvx --from litellm-brownout brownout check --gateway http://localhost:4000 --gateway-config brownout.config.yaml --manifest brownout.yaml
curl -sSf http://localhost:4000/user/delete \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" \
  -d '{"user_ids": ["brownout-init"]}'

Once the team's spend passes 90%, every {route} response carries these headers.

x-brownout-route-served: {fallback}
x-brownout-budget-tier: 90
x-brownout-degraded-from: {route}
x-brownout-degradation-reason: degrade_tier_reached

The fallback receives everything the route sends, tools and images included, so try it on the route's real requests first. To point Claude Code or Codex at a route, follow their setup. The lab drains a budget without spending anything.

Limits

  • Only text generation downgrades: embeddings, images, audio and Codex's /v1/responses/compact keep their model at any spend.
  • Requests name a model group: a router alias, a wildcard group such as openai/* or a list of models gets a 503.
  • No router fallbacks: a provider error on the chosen model reaches the caller. Failover between deployments of one model group still works.
  • The reservation comes first: LiteLLM reserves each request's worst case on the model the caller asked for. Set max_tokens, or a large request near the ceiling gets LiteLLM's 429 before the downgrade.
  • Redis is on the request path: while LiteLLM cannot reach Redis it refuses every budgeted request.

The full list covers the rest. If you run brownout on a real workload, open an issue with the model pair, budget window, threshold and LiteLLM version, and say whether the fallback stayed useful.

Documentation

License

MIT

Metadata

Release files for litellm-brownout 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 litellm-brownout 0.1.0
File Size Uploaded Provenance Actions
litellm_brownout-0.1.0.tar.gz 36.1 kB With provenance Details for litellm_brownout-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for litellm-brownout 0.1.0
File Interpreter ABI Platform Actions
litellm_brownout-0.1.0-py3-none-any.whl Python 3 none any Details for litellm_brownout-0.1.0-py3-none-any.whl

Total release size: 80.0 kB

Release files / litellm_brownout-0.1.0.tar.gz

Download URL litellm_brownout-0.1.0.tar.gz
Size 36.1 kB
Tags Source
SHA-256 checksum
How to use checksums
4beb521f66150b33e77fa26a1f3b4534b00f114cd56853c2cffd2cfdcef8549b
BLAKE2b-256 checksum
How to use checksums
45f2fcdd09e95625cd987d8b39562d9f64f8fc148685ae32e204152cf72eb8b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

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

Download URL litellm_brownout-0.1.0-py3-none-any.whl
Size 43.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c9c52c47b90d1c0cb3244764175fddb59acb95a2d7034e76e8adf1a8138f66b4
BLAKE2b-256 checksum
How to use checksums
517e125cd1beec98f5a8bbbadcc4407729091c4409171710b2343a1e1172da8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for litellm-brownout 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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for litellm_brownout-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full 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