BerriAI/litellm · error · HTTPException
max_budget cannot be negative. Received: {data.max_budget}
Error message
max_budget cannot be negative. Received: {data.max_budget} What it means
_check_team_project_limits rejects negative budgets before any DB write: NewProjectRequest/UpdateProjectRequest with max_budget < 0 returns HTTP 400 echoing the received value. It mirrors the equivalent team-level checks in team_endpoints.py.
Source
Thrown at enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py:143
team_object: LiteLLM_TeamTable,
data: NewProjectRequest | UpdateProjectRequest,
) -> None:
"""
Check that project limits respect its parent Team's limits.
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})"
},
)View on GitHub (pinned to 77b7c6c40c)
Solutions
- Omit max_budget entirely (null means unset) or send a non-negative value
- Use 0 to hard-block project spend, never a negative
- Fix client sentinel logic so unset numerics are omitted, not -1
Example fix
# before
{"team_id": "team-123", "project_alias": "p1", "max_budget": -1}
# after
{"team_id": "team-123", "project_alias": "p1", "max_budget": 100} Defensive patterns
Strategy: validation
Validate before calling
def sanitize_project_payload(data: dict) -> dict:
mb = data.get("max_budget")
if mb is not None and mb < 0:
raise ValueError(f"max_budget must be >= 0, got {mb}")
return data Type guard
def is_valid_budget(v) -> bool:
return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool) and v >= 0) Try / catch
try:
await post("/project/new", json=data)
except HTTPStatusError as e:
if e.response.status_code == 400 and "cannot be negative" in e.response.text:
data["max_budget"] = max(0, data["max_budget"]) # or drop the field
retry()
raise Prevention
- Validate budgets client-side before sending
- Never use -1 as an 'unset' sentinel in LiteLLM payloads — omit the field instead
When it happens
Trigger: POST /project/new or POST /project/update with "max_budget": -1 (or any negative number) in the payload.
Common situations: Clients using -1 as a 'no limit' sentinel; arithmetic like remaining - spent producing negatives; form defaults that initialize unset numerics to -1.
Related errors
- 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
- Model '{m}' not in team's allowed models. Team allowed model
- Project tpm_limit ({data.tpm_limit}) exceeds team's tpm_limi
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/5aee9827d6fb90c1.
Report an issue: GitHub.