Check for existing issues
What happened?
When calling POST /customer/update on an end-user that has no existing budget (budget_id=null, e.g. after the budget was deleted via /budget/delete which triggers FK ON DELETE SET NULL), and the request includes both max_budget and budget_duration, a new budget row is created in LiteLLM_BudgetTable, but budget_duration and budget_reset_at are silently set to null. Only max_budget is persisted on the new budget row.
The end-user appears to have a budget (budget_id is set, litellm_budget_table.max_budget is set), but the reset period is missing — so reset_budget_job never resets spend for this budget, and the customer effectively has a one-time non-resetting cap.
What did you expect to happen?
When /customer/update creates a new budget (because end_user_budget_table is None), it should persist budget_duration and compute budget_reset_at — exactly like /budget/new does (budget_management_endpoints.py:86-87):
if budget_obj.budget_reset_at is None and budget_obj.budget_duration is not None:
budget_obj.budget_reset_at = get_budget_reset_time(budget_duration=budget_obj.budget_duration)
Currently customer_endpoints.py (lines ~596-608) calls BudgetRepository(prisma_client).table.create(data=budget_table_data) directly without computing budget_reset_at from budget_duration, so both fields end up as null in the DB.
Steps to Reproduce
Setup: end-user must exist but have budget_id=null. Either create a fresh end-user with no budget, or delete its budget first.
# 1. Create end-user (skip if already exists)
curl -X POST "https://your-proxy.example.com/customer/new" \
-H "Authorization: Bearer sk-xxxx" \
-H "Content-Type: application/json" \
-d '{"user_id": "test-bug-repro@example.com"}'
# 2. Update end-user with max_budget + budget_duration (user has no existing budget)
curl -X POST "https://your-proxy.example.com/customer/update" \
-H "Authorization: Bearer sk-xxxx" \
-H "Content-Type: application/json" \
-d '{
"user_id": "test-bug-repro@example.com",
"max_budget": 50.0,
"budget_duration": "1mo"
}'
# 3. Fetch customer info — inspect litellm_budget_table
curl "https://your-proxy.example.com/customer/info?end_user_id=test-bug-repro@example.com" \
-H "Authorization: Bearer sk-xxxx"
Actual result (step 3):
{
"user_id": "test-bug-repro@example.com",
"litellm_budget_table": {
"budget_id": "69ec4697-4577-400e-9192-edeba7685837",
"max_budget": 50.0,
"budget_duration": null,
"budget_reset_at": null
}
}
Expected result:
{
"user_id": "test-bug-repro@example.com",
"litellm_budget_table": {
"budget_id": "...",
"max_budget": 50.0,
"budget_duration": "1mo",
"budget_reset_at": "2026-08-01T00:00:00.000Z"
}
}
Relevant log output
What part of LiteLLM is this about?
Proxy
What LiteLLM version are you on ?
v1.90
Twitter / LinkedIn details
No response
Check for existing issues
What happened?
When calling
POST /customer/updateon an end-user that has no existing budget (budget_id=null, e.g. after the budget was deleted via/budget/deletewhich triggers FK ON DELETE SET NULL), and the request includes bothmax_budgetandbudget_duration, a new budget row is created inLiteLLM_BudgetTable, butbudget_durationandbudget_reset_atare silently set tonull. Onlymax_budgetis persisted on the new budget row.The end-user appears to have a budget (
budget_idis set,litellm_budget_table.max_budgetis set), but the reset period is missing — soreset_budget_jobnever resets spend for this budget, and the customer effectively has a one-time non-resetting cap.What did you expect to happen?
When
/customer/updatecreates a new budget (becauseend_user_budget_table is None), it should persistbudget_durationand computebudget_reset_at— exactly like/budget/newdoes (budget_management_endpoints.py:86-87):Currently
customer_endpoints.py(lines ~596-608) callsBudgetRepository(prisma_client).table.create(data=budget_table_data)directly without computingbudget_reset_atfrombudget_duration, so both fields end up asnullin the DB.Steps to Reproduce
Setup: end-user must exist but have
budget_id=null. Either create a fresh end-user with no budget, or delete its budget first.Actual result (step 3):
{ "user_id": "test-bug-repro@example.com", "litellm_budget_table": { "budget_id": "69ec4697-4577-400e-9192-edeba7685837", "max_budget": 50.0, "budget_duration": null, "budget_reset_at": null } }Expected result:
{ "user_id": "test-bug-repro@example.com", "litellm_budget_table": { "budget_id": "...", "max_budget": 50.0, "budget_duration": "1mo", "budget_reset_at": "2026-08-01T00:00:00.000Z" } }Relevant log output
What part of LiteLLM is this about?
Proxy
What LiteLLM version are you on ?
v1.90
Twitter / LinkedIn details
No response