{"record":{"id":"4669c52b52e3f950","repo":"BerriAI/litellm","slug":"project-max-budget-data-max-budget-exceeds-tea","errorCode":null,"errorMessage":"Project max_budget ({data.max_budget}) exceeds team's max_budget ({team_object.max_budget}). Team: {team_object.team_id}","messagePattern":"Project max_budget \\((.+?)\\) exceeds team's max_budget \\((.+?)\\)\\. Team: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py","lineNumber":157,"sourceCode":"    project_models = data.models\n    team_models = team_object.models or []\n    if project_models and len(team_models) > 0:\n        # If team has 'all-proxy-models', skip validation as it allows all models\n        if SpecialModelNames.all_proxy_models.value not in team_models:\n            for m in project_models:\n                if m not in team_models:\n                    raise HTTPException(\n                        status_code=400,\n                        detail={\n                            \"error\": f\"Model '{m}' not in team's allowed models. Team allowed models={team_models}. Team: {team_object.team_id}\"\n                        },\n                    )\n\n    # --- Validate project max_budget <= team max_budget ---\n    # Team stores budget fields directly (max_budget, tpm_limit, rpm_limit)\n    # unlike Project which uses a separate LiteLLM_BudgetTable relation\n    if data.max_budget is not None and team_object.max_budget is not None and data.max_budget > team_object.max_budget:\n        raise HTTPException(\n            status_code=400,\n            detail={\n                \"error\": f\"Project max_budget ({data.max_budget}) exceeds team's max_budget ({team_object.max_budget}). Team: {team_object.team_id}\"\n            },\n        )\n\n    # --- Validate project tpm_limit <= team tpm_limit ---\n    if data.tpm_limit is not None and team_object.tpm_limit is not None and data.tpm_limit > team_object.tpm_limit:\n        raise HTTPException(\n            status_code=400,\n            detail={\n                \"error\": f\"Project tpm_limit ({data.tpm_limit}) exceeds team's tpm_limit ({team_object.tpm_limit}). Team: {team_object.team_id}\"\n            },\n        )\n\n    # --- Validate project rpm_limit <= team rpm_limit ---\n    if data.rpm_limit is not None and team_object.rpm_limit is not None and data.rpm_limit > team_object.rpm_limit:\n        raise HTTPException(","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py#L139-L175","documentation":"LiteLLM's hierarchical budget model requires a project's max_budget to not exceed its parent team's max_budget, so spending cannot bypass the team-level cap. If both the project request and the team row define max_budget and the project's value is larger, HTTP 400 is returned. The team stores budgets directly on LiteLLM_TeamTable (unlike projects, which use a separate LiteLLM_BudgetTable row).","triggerScenarios":"POST /project/new or PUT /project/update where data.max_budget > team_object.max_budget and both are non-null, e.g. team max_budget=100 and project max_budget=500. A None on either side skips the check.","commonSituations":"Creating a project budget larger than the team's without first raising the team cap, or reassigning a project to a team with a smaller budget via PUT /project/update with a new team_id.","solutions":["Lower the project's max_budget to at most the team's max_budget","Raise the team's max_budget first (PUT /team/update), then create/update the project","Omit max_budget on the project request if it should not have its own cap"],"exampleFix":"// before\nteam.max_budget = 100\nproject payload: {\"max_budget\": 500}\n// after\nteam.max_budget = 1000\nproject payload: {\"max_budget\": 500}","handlingStrategy":"validation","validationCode":"team = await client.get(f'/team/info?team_id={payload[\"team_id\"]}')\nteam_max = team.teams[0].max_budget\nif payload.get('max_budget') is not None and team_max is not None:\n    if payload['max_budget'] > team_max:\n        raise ValueError(f'project max_budget exceeds team cap {team_max}; raise the team budget first')","typeGuard":"const withinTeamBudget = (p, team) =>\n  p.max_budget == null || team.max_budget == null || p.max_budget <= team.max_budget;","tryCatchPattern":null,"preventionTips":["Model the hierarchy in config: team budgets are always >= sum of intended project budgets","When raising a project cap, script it as two steps: raise team, then project"],"tags":["litellm","budget","team","hierarchy","validation","enterprise","http-400"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}