{"record":{"id":"a6233e05d071ec22","repo":"BerriAI/litellm","slug":"soft-budget-cannot-be-negative-received-data-so","errorCode":null,"errorMessage":"soft_budget cannot be negative. Received: {data.soft_budget}","messagePattern":"soft_budget cannot be negative\\. Received: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py","lineNumber":123,"sourceCode":"\n    Mirrors _check_org_team_limits() from team_endpoints.py.\n\n    Validates:\n    - Project models are a subset of Team models\n    - Project max_budget <= Team max_budget\n    - Project tpm_limit <= Team tpm_limit\n    - Project rpm_limit <= Team rpm_limit\n    - Budget values are non-negative\n    - soft_budget < max_budget\n    \"\"\"\n    # --- Budget non-negativity checks ---\n    if data.max_budget is not None and data.max_budget < 0:\n        raise HTTPException(\n            status_code=400,\n            detail={\"error\": f\"max_budget cannot be negative. Received: {data.max_budget}\"},\n        )\n    if data.soft_budget is not None and data.soft_budget < 0:\n        raise HTTPException(\n            status_code=400,\n            detail={\"error\": f\"soft_budget cannot be negative. Received: {data.soft_budget}\"},\n        )\n\n    # --- soft_budget < max_budget ---\n    if data.soft_budget is not None and data.max_budget is not None:\n        if data.soft_budget >= data.max_budget:\n            raise HTTPException(\n                status_code=400,\n                detail={\n                    \"error\": f\"soft_budget ({data.soft_budget}) must be strictly lower than max_budget ({data.max_budget})\"\n                },\n            )\n\n    # --- Validate project models are a subset of team models ---\n    project_models = data.models\n    team_models = team_object.models or []\n    if project_models and len(team_models) > 0:","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py#L105-L141","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"project_id\": \"proj-1\", \"team_id\": \"team-1\", \"soft_budget\": -1}\n// after\n{\"project_id\": \"proj-1\", \"team_id\": \"team-1\", \"soft_budget\": null}","handlingStrategy":"validation","validationCode":"payload = {\"project_id\": \"p1\", \"team_id\": \"t1\", \"soft_budget\": -10}\nif payload.get(\"soft_budget\") is not None and payload[\"soft_budget\"] < 0:\n    payload[\"soft_budget\"] = None  # or raise locally with a clearer message\n# or clamp: payload[\"soft_budget\"] = max(0, payload[\"soft_budget\"])","typeGuard":"const hasValidSoftBudget = (p) =>\n  p.soft_budget === undefined || p.soft_budget === null || p.soft_budget >= 0;","tryCatchPattern":"try { await client.post('/project/new', payload) } catch (e) {\n  if (e.response?.status === 400 && /soft_budget cannot be negative/.test(e.response?.data?.detail?.error ?? '')) {\n    payload.soft_budget = null; return client.post('/project/new', payload);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["litellm","budget","validation","enterprise","http-400"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}