fix(proxy): block project requests when max_budget is 0

A project max_budget of 0 was treated as unbudgeted by #41354, while key budgets block at 0 and null is the unlimited value. Drop the <= 0 skip so 0 blocks and null stays unlimited
This commit is contained in:
ryan-crabbe-berri 2026-09-19 12:06:35 -07:00
parent eda1faba14
commit 162d6225e0
2 changed files with 7 additions and 6 deletions

View file

@ -5680,7 +5680,7 @@ async def _project_max_budget_check(
if project_object.litellm_budget_table is not None:
max_budget = project_object.litellm_budget_table.max_budget
if max_budget is None or max_budget <= 0 or not math.isfinite(max_budget):
if max_budget is None or not math.isfinite(max_budget):
return
from litellm.proxy.proxy_server import get_current_spend

View file

@ -7572,7 +7572,7 @@ async def test_project_allowlist_enforced_when_key_models_empty():
assert exc_info.value.code == "403"
def _project_with_budget(spend: float, max_budget: float):
def _project_with_budget(spend: float, max_budget: float | None):
from litellm.proxy._types import LiteLLM_BudgetTable, LiteLLM_ProjectTableCachedObj
return LiteLLM_ProjectTableCachedObj(
@ -7592,11 +7592,12 @@ def _project_with_budget(spend: float, max_budget: float):
pytest.param(4.99, 0.0, 5.0, False, id="counter-under-budget-admits"),
pytest.param(None, 5.0, 5.0, True, id="no-counter-falls-back-to-persisted-spend"),
pytest.param(None, 0.0, 5.0, False, id="no-counter-and-no-persisted-spend-admits"),
pytest.param(12.5, 12.5, 0.0, False, id="zero-budget-is-unbudgeted"),
pytest.param(12.5, 12.5, -1.0, False, id="negative-budget-is-unbudgeted"),
pytest.param(None, 0.0, 0.0, True, id="zero-budget-blocks-before-any-spend"),
pytest.param(12.5, 12.5, 0.0, True, id="zero-budget-blocks-with-spend"),
pytest.param(12.5, 12.5, None, False, id="null-budget-is-unlimited"),
],
)
async def test_project_max_budget_check_blocks_only_when_live_spend_reaches_a_positive_budget(
async def test_project_max_budget_check_blocks_when_live_spend_reaches_the_budget(
counter_spend, db_spend, max_budget, blocks
):
from litellm.caching.dual_cache import DualCache
@ -7631,7 +7632,7 @@ async def test_project_max_budget_check_blocks_only_when_live_spend_reaches_a_po
assert exc_info.value.entity_type == Litellm_EntityType.PROJECT.value
assert exc_info.value.entity_id == "p-budget"
assert exc_info.value.current_cost == 5.0
assert exc_info.value.current_cost == (db_spend if counter_spend is None else counter_spend)
proxy_logging_obj.budget_alerts.assert_awaited_once()
assert proxy_logging_obj.budget_alerts.await_args.kwargs["type"] == "project_budget"