BerriAI/litellm · error · ValueError

Invalid budget_reset_time {raw!r}; must be a quoted 24-hour

Error message

Invalid budget_reset_time {raw!r}; must be a quoted 24-hour 'HH:MM' string, e.g. "12:00"

What it means

ValueError from parse_budget_reset_time in litellm/proxy/common_utils/timezone_utils.py when the budget_reset_time config value is present but is not a string. The parser deliberately fails loudly at startup instead of silently resetting budgets at midnight. Non-string values almost always come from YAML type coercion (e.g. an unquoted 12:00 in YAML 1.1 is parsed as a sexagesimal integer) or from passing a datetime.time object where a quoted string is expected.

Source

Thrown at litellm/proxy/common_utils/timezone_utils.py:32

    module-level globals at call time.
    """

    model_config = ConfigDict(frozen=True)

    timezone: str = "UTC"
    reset_time_of_day: time = time(0, 0)


def parse_budget_reset_time(raw: object) -> time:
    """Parse a `budget_reset_time` config value (e.g. "12:00") into a `time`.

    Falls back to midnight when unset; raises a clear error on a malformed value
    so a bad config fails loudly at startup instead of silently resetting at midnight.
    """
    if raw is None or raw == "":
        return time(0, 0)
    if not isinstance(raw, str):
        raise ValueError(f"Invalid budget_reset_time {raw!r}; must be a quoted 24-hour 'HH:MM' string, e.g. \"12:00\"")
    for fmt in ("%H:%M", "%H:%M:%S"):
        try:
            parsed = datetime.strptime(raw, fmt)
            return time(hour=parsed.hour, minute=parsed.minute, second=parsed.second)
        except ValueError:
            continue
    raise ValueError(
        f"Invalid budget_reset_time {raw!r}; expected a 24-hour 'HH:MM' or 'HH:MM:SS' string, e.g. \"12:00\""
    )


def get_budget_reset_timezone() -> str:
    """
    Get the budget reset timezone from litellm_settings.
    Falls back to UTC if not specified.

    litellm_settings values are set as attributes on the litellm module
    by proxy_server.py at startup (via setattr(litellm, key, value)).

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Quote the value in YAML: budget_reset_time: "12:00".
  2. If building the config in Python, serialize with .strftime('%H:%M') or .isoformat() before dumping to YAML.
  3. Remove the budget_reset_time key entirely if midnight (00:00) is acceptable — None and empty string both fall back to midnight without erroring.

Example fix

# before (YAML 1.1 parses 12:00 as int 720 -> ValueError)
budget_reset_time: 12:00

# after
budget_reset_time: "12:00"
Defensive patterns

Strategy: validation

Validate before calling

from datetime import time

def validate_budget_reset_time(raw) -> time:
    if raw is None or raw == "":
        return time(0, 0)
    if not isinstance(raw, str):
        raise TypeError("budget_reset_time must be a quoted string like '12:00'")
    return raw  # string ok, format checked separately

Type guard

def is_valid_budget_reset_time_value(raw: object) -> bool:
    return raw is None or raw == "" or (isinstance(raw, str) and len(raw) >= 4 and raw[2] == ":")

Try / catch

try:
    from litellm.proxy.common_utils.timezone_utils import parse_budget_reset_time
    reset_at = parse_budget_reset_time(cfg.get("budget_reset_time"))
except ValueError as e:
    raise SystemConfigError(f"bad budget_reset_time: {e}") from e

Prevention

When it happens

Trigger: Setting budget_reset_time: 12:00 unquoted in proxy_config.yaml (PyYAML parses it as the int 720, not the string '12:00'); passing budget_reset_time as a datetime.time object programmatically; passing a number (budget_reset_time: 0) or any non-string YAML scalar to a virtual key budget config.

Common situations: Copying an example config that shows budget_reset_time: 12:00 without quotes; upgrading LiteLLM to a version that added strict validation where previously the value was ignored; generating config programmatically with yaml.dump of a time object.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/8b4c80c4377a8146. Report an issue: GitHub.