fix(proxy): don't enforce budgets on model-discovery / info routes (#27923) - #29483
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Greptile SummaryThis PR fixes a bug where an exhausted team, user, or organization budget caused
Confidence Score: 5/5Safe to merge — the change is a small, well-scoped addition to common_checks that only skips budget enforcement for six read-only, no-spend model-discovery routes. The production change is minimal: a frozenset constant and a two-line guard that sets an existing boolean flag. Authentication, RBAC, model-access, and route allow-listing are all unaffected. The narrowness of the frozenset (deliberately kept tighter than is_info_route) avoids unintended bypass of side-effectful endpoints. Regression tests cover the key scenarios, and no logic errors or data-path issues were found. No files require special attention beyond the minor test-maintainability note on test_auth_checks.py.
|
| Filename | Overview |
|---|---|
| litellm/proxy/auth/auth_checks.py | Adds a narrow MODEL_DISCOVERY_ROUTES frozenset and sets skip_budget_checks=True before entity budget gates when the route is a model-discovery endpoint, fixing #27923 without widening the exemption to side-effectful info routes. |
| tests/test_litellm/proxy/auth/test_auth_checks.py | Adds four regression tests for #27923 (team budget bypass, user budget bypass, /health/services still blocked, inference still blocked) but duplicates MODEL_DISCOVERY_ROUTES as a local list instead of importing the source-of-truth frozenset from auth_checks. |
Reviews (2): Last reviewed commit: "fix(proxy): narrow model-discovery budge..." | Re-trigger Greptile
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
Relevant issues
Fixes #27923
Pre-Submission checklist
make test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewType
🐛 Bug Fix
Changes
When a team, virtual key, organization, or user budget is exhausted, the proxy returned
429 Budget Exceededon the model-discovery endpoints (GET /v1/models,/models, and the/model/infofamily). Every OpenAI-compatible client (Open WebUI, Cursor, Aider, Continue, LibreChat, and others) callsGET /v1/modelsat startup to populate its model list, so an exhausted budget made all models invisible, including free or self-hosted ones, and broke the whole integration rather than just blocking paid inference.The cause was an inconsistency in
litellm/proxy/auth/auth_checks.py._global_proxy_budget_checkalready exempted/v1/modelsand/models, but the entity-level checks incommon_checks(team, virtual key, organization, user) ran inside a blanketif not skip_budget_checks:block with no route awareness, so they raisedBudgetExceededErroron discovery routes. Model listing runs no inference and incurs no spend, so it should never be budget-gated.The fix sets
skip_budget_checks = Trueincommon_checkswhen the route is a read-only model-discovery route. The exempt set is a small explicitfrozenset(MODEL_DISCOVERY_ROUTES) rather thanRouteChecks.is_info_route(). This is deliberate:info_routesalso contains side-effectful routes such as/health/services, whose handler can send Slack, email, and webhook test messages, and exempting those would let an out-of-budget key keep triggering them. Keeping the set narrow closes that hole while still fixing discovery. Only the budget-skip flag is touched, so authentication, route allow-listing, model-access, and RBAC checks are unchanged, and inference routes stay fully budget-enforced.The configurable
general_settingsbehavior the issue also proposes (return-all vs return-free-only vs block) is intentionally left out so this PR stays isolated to the bug; it can follow separately.Regression tests live in
tests/test_litellm/proxy/auth/test_auth_checks.py: the six discovery routes are allowed under an exhausted team and user budget,/health/servicesand/v1/chat/completionsstill raiseBudgetExceededError. The/health/servicescase is the mutation guard; widening the exemption back tois_info_route()fails it.Screenshots / Proof of Fix
Run a local proxy against a config that has at least one real model and a master key:
Create a virtual key with a tiny budget so the first real call exhausts it, then drive one real completion to push spend over budget (this hits a live provider and costs a few cents):
Now the key is over budget. Model discovery succeeds and inference is still blocked:
To see the old behavior for contrast, check out
litellm_internal_staging, restart the proxy, and repeat the two curls above:GET /v1/modelsreturns429there.