-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Description
What happened?
Bug Description
The get_next_standardized_reset_time() function in litellm/litellm_core_utils/duration_parser.py has a critical bug that causes incorrect budget reset time calculations when large duration values are specified in seconds, minutes, or hours. The bug affects _handle_second_reset(), _handle_minute_reset(), and _handle_hour_reset() functions.
Problem
When calculating reset times for durations that span multiple days, these functions only add 1 day to the reset time regardless of how many days the duration actually spans. This causes budget resets to be scheduled far too early.
Example Scenario
Working correctly:
budget_duration: "365d"→ Correctly calculates reset time 365 days in the future
Broken:
budget_duration: "31536000s"(1 year in seconds) → Incorrectly calculates reset time ~1 day in the future instead of 365 days
Root Cause
In _handle_second_reset() (lines 318-364):
# Calculate next second aligned with the value
# ... calculation logic ...
# Handle overnight case
if next_hour >= 24:
next_hour = next_hour % 24
next_day = base_midnight + timedelta(days=1) # BUG: Only adds 1 day!
return next_day.replace(
hour=next_hour, minute=next_minute, second=next_second, microsecond=0
)When value is large (e.g., 31,536,000 seconds), next_hour will be an enormous number. The code wraps it with % 24 but then only adds timedelta(days=1) instead of calculating the actual number of days.
Same Bug Exists In:
-
_handle_minute_reset()(lines 306-311):if next_hour >= 24: next_hour = next_hour % 24 next_day = base_midnight + timedelta(days=1) # BUG
-
_handle_hour_reset()(lines 266-269):if next_hour >= 24: next_hour = next_hour % 24 next_day = base_midnight + timedelta(days=1) # BUG
Proposed Fix
Calculate the actual number of days from the hour overflow:
For _handle_second_reset():
# Handle overnight case
if next_hour >= 24:
extra_days = next_hour // 24
next_hour = next_hour % 24
next_day = base_midnight + timedelta(days=extra_days)
return next_day.replace(
hour=next_hour, minute=next_minute, second=next_second, microsecond=0
)For _handle_minute_reset():
# Handle overnight case
if next_hour >= 24:
extra_days = next_hour // 24
next_hour = next_hour % 24
next_day = base_midnight + timedelta(days=extra_days)
return next_day.replace(
hour=next_hour, minute=next_minute, second=0, microsecond=0
)For _handle_hour_reset():
# Handle overnight case
if next_hour >= 24:
extra_days = next_hour // 24
next_hour = next_hour % 24
next_day = base_midnight + timedelta(days=extra_days)
return next_day.replace(hour=next_hour)Impact
This bug affects:
- Budget management: Keys/users/teams with large
budget_durationvalues in seconds/minutes/hours will have their budgets reset far too frequently - Cost control: Organizations relying on long-term budget resets (e.g., annual budgets) could experience unexpected resets
- API key management: Keys with long validity periods specified in non-day units will expire prematurely
Comparison with Working Code
The _handle_day_reset() function correctly handles this case (lines 232-235):
else: # Custom day value - next interval is value days from current
return current_time.replace(
hour=0, minute=0, second=0, microsecond=0
) + timedelta(days=value) # ✓ Correctly adds all daysWorkaround
Until fixed, users should specify large durations using days ("365d") rather than equivalent values in seconds ("31536000s"), minutes ("525600m"), or hours ("8760h").
Environment
- File:
litellm/litellm_core_utils/duration_parser.py - Functions affected:
_handle_second_reset(),_handle_minute_reset(),_handle_hour_reset() - Version: Latest (as of December 2025)
Severity
High - This bug can cause significant issues with budget management and cost controls in production environments when large duration values are used.
Relevant log output
Are you a ML Ops Team?
No
What LiteLLM version are you on ?
v1.80.10.rc.2
Twitter / LinkedIn details
No response