BerriAI/litellm · error · ValueError
Invalid duration format
Error message
Invalid duration format
What it means
_extract_from_regex in litellm's duration parser matches durations against r'(\d+)(mo|[smhdw]?)'. If re.match finds nothing — i.e. the string does not start with one or more digits — it raises 'Invalid duration format'. This is the first validation gate for budget/reset duration strings like '30d', '1mo', '12h'.
Source
Thrown at litellm/litellm_core_utils/duration_parser.py:33
from litellm._logging import verbose_logger
_BUDGET_DURATION_WORD_ALIASES: Final[dict[str, str]] = {
"hourly": "1h",
"daily": "24h",
"weekly": "7d",
"monthly": "30d",
}
def _normalize_duration(duration: str) -> str:
return _BUDGET_DURATION_WORD_ALIASES.get(duration.strip().lower(), duration)
def _extract_from_regex(duration: str) -> tuple[int, str]:
match: Final = re.match(r"(\d+)(mo|[smhdw]?)", duration)
if not match:
raise ValueError("Invalid duration format")
value, unit = match.groups()
value = int(value)
return value, unit
def get_last_day_of_month(year, month):
# Handle December case
if month == 12:
return 31
# Next month is January, so subtract a day from March 1st
next_month: Final = datetime(year=year, month=month + 1, day=1)
last_day_of_month: Final = (next_month - timedelta(days=1)).day
return last_day_of_month
def duration_in_seconds(duration: str) -> int:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Use the supported integer+unit form: '<n>' (seconds), '10s', '10m', '10h', '10d', '10w', or '1mo'.
- If free text is accepted upstream, map words through the alias table or your own dict before handing it to litellm, defaulting unknowns rather than passing them through.
- Validate early with re.match(r'(\d+)(mo|[smhdw]?)', value) and reject/normalize before the call.
Example fix
# before
budget_duration="one day" # no leading digits -> raises
# after
budget_duration="1d" # integer + supported unit
# or pre-map: {"day":"1d", "week":"1w"}.get(user_input.lower(), "30d") Defensive patterns
Strategy: validation
Validate before calling
import re
_DURATION_RE = re.compile(r"^(\d+)(mo|[smhdw]?)$")
def is_parseable_duration(v: str) -> bool:
return bool(_DURATION_RE.match(v.strip()))
assert is_parseable_duration("30d")
assert not is_parseable_duration("one day") Type guard
import re
def is_duration_string(v: object) -> bool:
"""True for litellm-supported '<int><unit>' durations (s/m/h/d/w/mo)."""
return isinstance(v, str) and bool(re.match(r"^(\d+)(mo|[smhdw]?)$", v.strip())) Try / catch
from litellm.litellm_core_utils.duration_parser import _extract_from_regex
try:
value, unit = _extract_from_regex(duration)
except ValueError:
duration = "30d" # explicit, logged default — never silently reinterpret
value, unit = _extract_from_regex(duration) Prevention
- Constrain duration inputs to a dropdown/enum of supported strings.
- Wrap free-text durations in your own word->value map before passing through.
- Anchored-regex validate at the config boundary (^...$) to catch trailing junk early.
When it happens
Trigger: Passing a duration with no leading digits: 'one day', 'day', '', 'sec', or 'monthly' after alias normalization fails ('monthly' is aliased to '30d', but an unlisted word like 'week' or 'biweekly' is not). Also negative or float inputs ('-1d', '0.5h') since the regex demands integer digits at position 0.
Common situations: Setting budget_duration in config.yaml from user input or a form field; upgrading from values that previously fell through to a default; locale-dependent words ('monat') not in the alias map.
Related errors
- Unsupported duration unit, passed duration: {duration}
- Monthly resets currently only support 1 month intervals
- soft_budget cannot be negative. Received: {data.soft_budget}
- soft_budget ({data.soft_budget}) must be strictly lower than
- Project max_budget ({data.max_budget}) exceeds team's max_bu
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/b1060246b5cfd241.
Report an issue: GitHub.