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

  1. Set soft_budget to a non-negative value or omit it entirely (None skips the check)
  2. If the intent was 'no soft budget', send null instead of -1
  3. 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

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


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/a6233e05d071ec22. Report an issue: GitHub.