From 4a916d9e0ba48a6c9b1561af0f7bb74ffb800f7c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 3 Sep 2026 14:00:28 +0000 Subject: [PATCH] fix(proxy): clear LIT002/LIT011 on empty budget_duration paths Replace the unit membership set with a match so the parser does not build a mutable collection. Stop writing budget_duration on updated_kv when the duration is blank Co-authored-by: Zsanz3 --- litellm/litellm_core_utils/duration_parser.py | 30 +++++++++++-------- .../management_endpoints/team_endpoints.py | 1 - .../test_team_endpoints.py | 1 - 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/litellm/litellm_core_utils/duration_parser.py b/litellm/litellm_core_utils/duration_parser.py index 414369e35c6..89786086dbf 100644 --- a/litellm/litellm_core_utils/duration_parser.py +++ b/litellm/litellm_core_utils/duration_parser.py @@ -134,24 +134,30 @@ def get_next_standardized_reset_time( current_time, _ = _setup_timezone(current_time, timezone_str) value, unit = _parse_duration(_normalize_duration(duration)) - if value is None or unit not in {"s", "m", "h", "d", "w", "mo"}: + if value is None: raise ValueError( f"Invalid budget_duration {duration!r}. Use the format (e.g. '1h', '7d', '30d', '1mo')." ) base_midnight: Final = current_time.replace(hour=0, minute=0, second=0, microsecond=0) - if unit == "d": - return _handle_day_reset(current_time, base_midnight, value, reset_time_of_day) - elif unit == "w": - return _handle_day_reset(current_time, base_midnight, value * 7, reset_time_of_day) - elif unit == "h": - return _handle_hour_reset(current_time, base_midnight, value) - elif unit == "m": - return _handle_minute_reset(current_time, base_midnight, value) - elif unit == "s": - return _handle_second_reset(current_time, base_midnight, value) - return _handle_month_reset(current_time, base_midnight, value, reset_time_of_day) + match unit: + case "d": + return _handle_day_reset(current_time, base_midnight, value, reset_time_of_day) + case "w": + return _handle_day_reset(current_time, base_midnight, value * 7, reset_time_of_day) + case "h": + return _handle_hour_reset(current_time, base_midnight, value) + case "m": + return _handle_minute_reset(current_time, base_midnight, value) + case "s": + return _handle_second_reset(current_time, base_midnight, value) + case "mo": + return _handle_month_reset(current_time, base_midnight, value, reset_time_of_day) + case _: + raise ValueError( + f"Invalid budget_duration {duration!r}. Use the format (e.g. '1h', '7d', '30d', '1mo')." + ) def _setup_timezone(current_time: datetime, timezone_str: str = "UTC") -> tuple[datetime, tzinfo]: diff --git a/litellm/proxy/management_endpoints/team_endpoints.py b/litellm/proxy/management_endpoints/team_endpoints.py index 44733fd3cd9..58f6c40abe8 100644 --- a/litellm/proxy/management_endpoints/team_endpoints.py +++ b/litellm/proxy/management_endpoints/team_endpoints.py @@ -2422,7 +2422,6 @@ def _set_budget_reset_at(data: UpdateTeamRequest, updated_kv: dict) -> None: elif data.budget_duration is not None or ( "budget_duration" in updated_kv and updated_kv["budget_duration"] is None ): - updated_kv["budget_duration"] = None updated_kv["budget_reset_at"] = None if data.budget_limits is not None and len(data.budget_limits) > 0: diff --git a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py index 63e848398c0..ef85e6c321f 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py @@ -550,7 +550,6 @@ def test_set_budget_reset_at_treats_a_blank_duration_as_unset(blank): _set_budget_reset_at(data, updated_kv) - assert updated_kv["budget_duration"] is None assert updated_kv["budget_reset_at"] is None