If you resell LLM access, you already know the failure mode: a customer burns through their monthly allowance mid-session and every request after that returns an error. Technically correct, commercially awful. The per-key max_budget that stops them from draining your account also stops them from getting an answer.
LiteLLM v1.92.x added a cleaner move: budget_fallbacks. When a key crosses its cap for one model, the same request is silently rerouted to a cheaper model that still has headroom. Your user gets a (slightly worse) answer instead of a 4xx, and your bill still has a ceiling. Here's the whole thing.
The one-line difference from a normal budget#
A per-key max_budget is a wall. Cross it and the proxy raises BudgetExceededError before the request ever reaches a model:
ExceededBudget: Current spend: 20.4; Max Budget: 20.0
budget_fallbacks turns that wall into a slide. It works per model on the key: you cap each model, and you name an ordered chain of models to fall to when a cap is hit. This is different from router-level fallbacks (which fire on errors like a 500 or a rate limit) — budget fallbacks fire on spend, and they're configured on the key itself, not in config.yaml.
Set it on the key#
You set two fields when you mint the virtual key. model_max_budget is a dict of per-model caps, each with a budget_limit (USD) and a time_period. budget_fallbacks is a dict mapping each capped model to the ordered chain of models to try instead:
curl 'http://0.0.0.0:4000/key/generate' \
--header 'Authorization: Bearer sk-1234' \
--header 'Content-Type: application/json' \
--data '{
"model_max_budget": {
"claude-opus": {"budget_limit": 20.0, "time_period": "1d"},
"claude-sonnet": {"budget_limit": 5.0, "time_period": "1d"}
},
"budget_fallbacks": {
"claude-opus": ["claude-sonnet", "claude-haiku"],
"claude-sonnet": ["claude-haiku"]
}
}'
Read that as a policy: this user gets \$20/day of Opus; once that's gone, route them to Sonnet; once Sonnet's \$5/day is gone, route them to Haiku. The user's client never changes — they keep calling model: "claude-opus". The proxy quietly does the downgrade.
What actually happens on a request#
The reroute is deliberately narrow. LiteLLM applies it only when all three are true for the requested model:
- The key has a
model_max_budgetentry for that model, and - Accumulated spend on that model has crossed its
budget_limit, and - The key has a
budget_fallbacksentry for that model.
When they hold, LiteLLM walks the fallback chain in order and picks the first model that is itself within budget — either because it has no cap, or because its own cap hasn't been reached yet. If every model in the chain is also over budget, the original BudgetExceededError is raised. So the ceiling never disappears; it just gets a soft landing on the way down.
Budget fallbacks degrade quality gracefully. They do not remove the ceiling — they add rungs to it.
The gotcha: spend follows the fallback#
The one thing that surprises people: spend is attributed to the fallback model, not the exhausted one. Once Opus is tapped out and traffic slides to Sonnet, those dollars accrue to Sonnet's counter on the same key. That's usually what you want — it means Sonnet can eventually hit its \$5 cap and cascade down to Haiku, exactly as the chain describes. But it also means a long-running abusive session doesn't get free rein on the cheap model; it just walks down your chain until it hits a model with no fallback left, and then it errors. Design the last rung of every chain to be a model you're comfortable serving unmetered, or leave it capped so the chain terminates in an honest error.
When to reach for this vs. a hard stop#
- Hard stop (
max_budgetalone): internal tools, free-tier abuse control, anything where "you're out of credits" is the correct, expected answer. - Budget fallbacks: paid products where a mid-session failure costs you more than a cheaper completion does. A support agent that drops from Opus to Haiku at the end of the month still answers the ticket.
Two things this is not: it's not error-handling (for 500s and rate limits you still want router fallbacks and retries), and it's not a cost-aware router that picks the cheapest capable model up front. It's the last line: the thing that decides what happens after the money for the good model is already gone. Set it once per key, and "out of budget" stops meaning "out of service."



