BerriAI/litellm · error · ValueError
duration needs to be one of ["daily", "weekly", "monthly", "
Error message
duration needs to be one of ["daily", "weekly", "monthly", "yearly"]
What it means
ValueError from BudgetManager.create_budget: the 'duration' argument must be one of the four literals 'daily', 'weekly', 'monthly', 'yearly'. The value is mapped to an internal day count (1/7/30/365) that drives budget-window reset; anything else — including abbreviations, plurals like 'days', or numeric durations — is rejected.
Source
Thrown at litellm/budget_manager.py:92
total_budget: float,
user: str,
duration: Literal["daily", "weekly", "monthly", "yearly"] | None = None,
created_at: float = time.time(),
):
self.user_dict[user] = {"total_budget": total_budget}
if duration is None:
return self.user_dict[user]
if duration == "daily":
duration_in_days = 1
elif duration == "weekly":
duration_in_days = DAYS_IN_A_WEEK
elif duration == "monthly":
duration_in_days = DAYS_IN_A_MONTH
elif duration == "yearly":
duration_in_days = DAYS_IN_A_YEAR
else:
raise ValueError("""duration needs to be one of ["daily", "weekly", "monthly", "yearly"]""")
self.user_dict[user] = {
"total_budget": total_budget,
"duration": duration_in_days,
"created_at": created_at,
"last_updated_at": created_at,
}
self._save_data_thread() # [Non-Blocking] Update persistent storage without blocking execution
return self.user_dict[user]
def projected_cost(self, model: str, messages: list, user: str):
text: Final = "".join(message["content"] for message in messages)
prompt_tokens: Final = litellm.token_counter(model=model, text=text)
prompt_cost, _ = litellm.cost_per_token(model=model, prompt_tokens=prompt_tokens, completion_tokens=0)
current_cost: Final = self.user_dict[user].get("current_cost", 0)
projected_cost: Final = prompt_cost + current_cost
return projected_cost
def get_total_budget(self, user: str):View on GitHub (pinned to 6c2dcb801b)
Solutions
- Use an exact literal: duration='daily' | 'weekly' | 'monthly' | 'yearly'.
- If durations come from config, map/validate them before calling create_budget.
- For custom windows, file a feature request — only the four fixed windows are supported.
Example fix
# before budget_manager.create_budget(total_budget=10, user="u1", duration="30d") # after budget_manager.create_budget(total_budget=10, user="u1", duration="monthly")
Defensive patterns
Strategy: validation
Validate before calling
VALID_DURATIONS = {"daily", "weekly", "monthly", "yearly"}
if duration not in VALID_DURATIONS:
raise ValueError(f"duration must be one of {sorted(VALID_DURATIONS)}, got {duration!r}") Type guard
def is_valid_budget_duration(v) -> bool:
return isinstance(v, str) and v in {"daily", "weekly", "monthly", "yearly"} Prevention
- Map config strings (30d, 1mo) to the four literals in a normalizer before calling create_budget.
- Cover budget creation in config tests so invalid durations fail at deploy time.
- Remember casing matters: lowercase only.
When it happens
Trigger: Calling budget_manager.create_budget(total_budget=100, user='u', duration='30d') or duration='month', duration=30, duration=None-with-total_budget — any value not exactly matching one of the four literals. (duration=None takes a different branch and returns existing data.)
Common situations: Config files with '30d'/'1mo' style durations from other tools; passing a number of days expecting custom windows; casing issues like 'Monthly' (must be lowercase).
Related errors
- Either a chat completion object or the text response needs t
- otel.attributes must be a mapping with optional 'include_lis
- otel.attributes: include_list and exclude_list are mutually
- otel.attributes: {TOKEN_TYPE_ATTRIBUTE} is a structural toke
- Invalid mode: {custom_auth_settings['mode']}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/1efd87f4188979a3.
Report an issue: GitHub.