From ea509ec6b99e87c6d23779c2c35da25906be1d0c Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Fri, 17 Apr 2026 17:32:39 -0700 Subject: [PATCH] Run key budget alert check before max-budget enforcement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _virtual_key_max_budget_check raises BudgetExceededError when spend crosses max_budget, which meant the 100% threshold in the multi-threshold email config never got a chance to fire — the request that pushes spend over 100% was rejected before the alert check ran. Reorder so the alert check runs first; enforcement still raises right after. --- litellm/proxy/auth/user_api_key_auth.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index ebabf4cdb56..94b1720545c 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -1373,7 +1373,16 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 if not skip_budget_checks: with tracer.trace("litellm.proxy.auth.budget_checks"): - # Check 4. Token Spend is under budget + # Check 4. Max Budget Alert Check (runs before budget enforcement + # so multi-threshold 100% alerts fire on the request that crosses + # max_budget, before BudgetExceededError is raised below) + await _virtual_key_max_budget_alert_check( + valid_token=valid_token, + proxy_logging_obj=proxy_logging_obj, + user_obj=user_obj, + ) + + # Check 5. Token Spend is under budget if RouteChecks.is_llm_api_route(route=route): await _virtual_key_max_budget_check( valid_token=valid_token, @@ -1381,13 +1390,6 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 user_obj=user_obj, ) - # Check 5. Max Budget Alert Check - await _virtual_key_max_budget_alert_check( - valid_token=valid_token, - proxy_logging_obj=proxy_logging_obj, - user_obj=user_obj, - ) - # Check 6. Soft Budget Check await _virtual_key_soft_budget_check( valid_token=valid_token,