BerriAI/litellm · error · HTTPException
soft_budget cannot be negative. Received: {data.soft_budget}
Error message
soft_budget cannot be negative. Received: {data.soft_budget} What it means
Raised by the LiteLLM Enterprise proxy when creating or updating a project with a negative soft_budget value. soft_budget is the threshold at which budget alerts fire for a project, so it must be zero or positive. The check runs in _check_team_project_limits before any database write, returning HTTP 400.
Source
Thrown at enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py:123
Mirrors _check_org_team_limits() from team_endpoints.py.
Validates:
- Project models are a subset of Team models
- Project max_budget <= Team max_budget
- Project tpm_limit <= Team tpm_limit
- Project rpm_limit <= Team rpm_limit
- Budget values are non-negative
- soft_budget < max_budget
"""
# --- Budget non-negativity checks ---
if data.max_budget is not None and data.max_budget < 0:
raise HTTPException(
status_code=400,
detail={"error": f"max_budget cannot be negative. Received: {data.max_budget}"},
)
if data.soft_budget is not None and data.soft_budget < 0:
raise HTTPException(
status_code=400,
detail={"error": f"soft_budget cannot be negative. Received: {data.soft_budget}"},
)
# --- soft_budget < max_budget ---
if data.soft_budget is not None and data.max_budget is not None:
if data.soft_budget >= data.max_budget:
raise HTTPException(
status_code=400,
detail={
"error": f"soft_budget ({data.soft_budget}) must be strictly lower than max_budget ({data.max_budget})"
},
)
# --- Validate project models are a subset of team models ---
project_models = data.models
team_models = team_object.models or []
if project_models and len(team_models) > 0:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Set soft_budget to a non-negative value or omit it entirely (None skips the check)
- If the intent was 'no soft budget', send null instead of -1
- Recompute derived budget values with max(0, value) before sending the request
Example fix
// before
{"project_id": "proj-1", "team_id": "team-1", "soft_budget": -1}
// after
{"project_id": "proj-1", "team_id": "team-1", "soft_budget": null} Defensive patterns
Strategy: validation
Validate before calling
payload = {"project_id": "p1", "team_id": "t1", "soft_budget": -10}
if payload.get("soft_budget") is not None and payload["soft_budget"] < 0:
payload["soft_budget"] = None # or raise locally with a clearer message
# or clamp: payload["soft_budget"] = max(0, payload["soft_budget"]) Type guard
const hasValidSoftBudget = (p) => p.soft_budget === undefined || p.soft_budget === null || p.soft_budget >= 0;
Try / catch
try { await client.post('/project/new', payload) } catch (e) {
if (e.response?.status === 400 && /soft_budget cannot be negative/.test(e.response?.data?.detail?.error ?? '')) {
payload.soft_budget = null; return client.post('/project/new', payload);
}
throw e;
} Prevention
- Normalize derived budget numbers with max(0, x) before building the payload
- Treat null, not -1, as the 'unset' value for budgets in your provisioning code
When it happens
Trigger: POST /project/new or PUT /project/update with JSON body where soft_budget is a negative number (e.g. "soft_budget": -10), while max_budget validation already passed. Even -0.01 triggers it because the guard is data.soft_budget < 0.
Common situations: Passing a sentinel value like -1 for 'no budget', computing soft_budget from a subtraction that can go negative, or copy-pasting a template with placeholder negative values.
Related errors
- soft_budget ({data.soft_budget}) must be strictly lower than
- Project max_budget ({data.max_budget}) exceeds team's max_bu
- Model '{m}' not in team's allowed models. Team allowed model
- Project tpm_limit ({data.tpm_limit}) exceeds team's tpm_limi
- Project rpm_limit ({data.rpm_limit}) exceeds team's rpm_limi
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/a6233e05d071ec22.
Report an issue: GitHub.