Skip to content

fix(router): treat a max_budget of zero as a hard stop - #43277

Open
abeed09 wants to merge 5 commits into
BerriAI:mainfrom
abeed09:cursor/router-zero-budget-blocks-spend-e485
Open

abeed09 wants to merge 5 commits into
BerriAI:mainfrom
abeed09:cursor/router-zero-budget-blocks-spend-e485

Conversation

@abeed09

@abeed09 abeed09 commented Sep 26, 2026

Copy link
Copy Markdown

TLDR

Problem this solves:

  • A provider, deployment, or tag budget of $0 was ignored
  • Those routes kept taking traffic after the cap was set

How it solves it:

  • A configured cap is enforced, including a cap of 0
  • An empty provider cap no longer skips that deployment's other caps
  • The deployment over-budget line prints the dollar cap

Intentional product change: max_budget 0 now blocks spend on that provider, deployment, or tag. A provider budget entry with a time window and no dollar amount no longer removes its deployments

User Flow

Before: an admin who sets a provider budget of zero still sees that provider serve traffic

  1. They set the OpenAI budget to 0 dollars for 1 day
  2. A client requests a model on that provider, even after it has already spent money
  3. The request succeeds and that deployment stays in the rotation

After: the same budget rejects the request before it is sent

  1. They set the OpenAI budget to 0 dollars for 1 day
  2. A client requests a model on that provider, including when recorded spend is still zero
  3. The request fails with "No deployments available - crossed budget: Exceeded budget for provider openai: 0.0 >= 0.0"
  4. A sibling provider with no cap still serves, and a deployment or tag cap of 0 fails the same way

Relevant issues

Fixes #43214

Pre-Submission checklist

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Screenshots / Proof of Fix

Python router, mock_response set so an allowed call does not leave the process. A blocked call errors before any provider request, so there is no provider charge. This is the same in-process router path as the issue

Before (1a58162)

Provider already spent $50 against a $0 cap

  1. Filter OpenAI with max_budget=0, budget_duration=1d, and recorded spend 50.0
  2. Observed routable=True and debug=''

Router completion with provider max_budget 0 and no recorded spend

  1. Router.acompletion for openai/gpt-4 with mock_response set
  2. Observed served: served

Router completion with provider max_budget 0.01 and no recorded spend

  1. Same completion with max_budget=0.01
  2. Observed served: served

After (6214d5d)

Provider already spent $50 against a $0 cap

  1. Same filter as before
  2. Observed routable=False and debug='Exceeded budget for provider openai: 50.0 >= 0.0\n'

Router completion with provider max_budget 0 and no recorded spend

  1. Same Router.acompletion as before
  2. Observed ValueError: No deployments available - crossed budget: Exceeded budget for provider openai: 0.0 >= 0.0

Router completion with provider max_budget 0.01 and no recorded spend

  1. Same completion with max_budget=0.01
  2. Observed served: served

Deployment max_budget 0

  1. One deployment with litellm_params.max_budget=0 and budget_duration=1d, then the same completion
  2. Observed ValueError: No deployments available - crossed budget: Exceeded budget for deployment model_name: gpt-4, litellm_params.model: openai/gpt-4, model_id: dep-1: 0.0 >= 0.0

Mutation: putting the truthy if config.max_budget and spend >= cap check back fails 6 of the new cases: provider zero, deployment zero, tag zero, an unset provider cap, and the deployment message that used to print the time window

Type

Bug Fix

Caveats

Low

  • A provider entry with a time window and no dollar cap used to drop its deployments
  • Those deployments stay routable now, and a deployment or tag cap on them still applies

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

cursoragent and others added 2 commits September 26, 2026 02:46
A provider, deployment, or tag cap of 0 was skipped because the
spend check used the dollar amount as a boolean. Compare against
None instead, and keep checking deployment and tag caps when a
provider entry has no dollar limit.

Co-authored-by: abeed09 <abeed09@users.noreply.github.com>
The provider, deployment, and tag checks share one parametrized
test, plus the case where an empty provider cap must still honor
a deployment cap.

Co-authored-by: abeed09 <abeed09@users.noreply.github.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@codspeed

codspeed Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing abeed09:cursor/router-zero-budget-blocks-spend-e485 (72e1c69) with main (d08746f)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (4eb340a) during the generation of this report, so d08746f was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@codecov

codecov Bot commented Sep 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@abeed09

abeed09 commented Sep 26, 2026

Copy link
Copy Markdown
Author

@greptileai

@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Changes budget enforcement logic in the router.

The PR appears safe to merge; no outstanding findings remain.

Summary

The PR makes a configured zero-dollar provider, deployment, or tag budget exclude a deployment from routing. It also lets deployment and tag checks run when a provider cap is unset, corrects the deployment-budget message, and adds filter-level and Router-level tests.

Reviews (5) · Last reviewed commit: "test(router): annotate the budget filter..."

Comment thread tests/unit/router_strategy/test_budget_limiter.py Outdated
A hand-built spend map never asks the router which deployment it
would send. Route a mocked completion through Router and require the
uncapped sibling, with the zero-cap provider weighted so it would win
if the filter left it eligible.

Co-authored-by: abeed09 <abeed09@users.noreply.github.com>
@abeed09

abeed09 commented Sep 26, 2026

Copy link
Copy Markdown
Author

@greptileai

Comment thread tests/unit/router_strategy/test_budget_limiter.py Outdated
Comment thread tests/unit/router_strategy/test_budget_limiter.py Outdated
Each zero-budget case is built once and passed through. The router
deployment uses DeploymentTypedDict, the model list entry type.

Co-authored-by: abeed09 <abeed09@users.noreply.github.com>
@abeed09

abeed09 commented Sep 26, 2026

Copy link
Copy Markdown
Author

@greptileai

Comment thread tests/unit/router_strategy/test_budget_limiter.py Outdated
The two helpers return the deployments the filter kept and the debug
string. Name that as a sequence of model-list entries.

Co-authored-by: abeed09 <abeed09@users.noreply.github.com>
@abeed09

abeed09 commented Sep 26, 2026

Copy link
Copy Markdown
Author

@greptileai

@abeed09

abeed09 commented Sep 26, 2026

Copy link
Copy Markdown
Author

The remaining Unit Tests failure is unrelated to this PR: duplicate openrouter/perceptron/perceptron-mk1.5 cost-map entries. #43273 fixes the same upstream failure.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RouterBudgetLimiting treats max_budget=0 as unlimited instead of blocking all spend (provider/deployment/tag)

3 participants