{"record":{"id":"69d860f7bff1118b","repo":"BerriAI/litellm","slug":"only-admins-can-delete-projects","errorCode":null,"errorMessage":"Only admins can delete projects","messagePattern":"Only admins can delete projects","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py","lineNumber":772,"sourceCode":"                },\n            )\n\n        if prisma_client is None:\n            raise HTTPException(\n                status_code=500,\n                detail={\"error\": CommonProxyErrors.db_not_connected_error.value},\n            )\n\n        # Check if user is admin (only admins can delete projects)\n        has_permission = await _check_user_permission_for_project(\n            user_api_key_dict=user_api_key_dict,\n            team_id=None,\n            prisma_client=prisma_client,\n            require_admin=True,\n        )\n\n        if not has_permission:\n            raise HTTPException(\n                status_code=403,\n                detail={\"error\": \"Only admins can delete projects\"},\n            )\n\n        deleted_projects: list[prisma_models.LiteLLM_ProjectTable | None] = []\n\n        for project_id in data.project_ids:\n            # Check if project exists\n            existing_project = await _project_table(prisma_client).find_unique(where={\"project_id\": project_id})\n\n            if existing_project is None:\n                raise ProxyException(\n                    message=f\"Project not found, project_id={project_id}\",\n                    type=\"not_found\",\n                    code=404,\n                    param=\"project_ids\",\n                )\n","sourceCodeStart":754,"sourceCodeEnd":790,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py#L754-L790","documentation":"Deletion is admin-only: _check_user_permission_for_project is invoked with team_id=None and require_admin=True, which only proxy-admin roles satisfy. Team admins — who may create and update projects — explicitly cannot delete them.","triggerScenarios":"POST /project/delete with any non-proxy-admin key: a team admin, internal user, or org member credential.","commonSituations":"Assuming CRUD permissions are symmetric for team admins; cleanup scripts running with a scoped team key; SSO role mapping that leaves the key's user below proxy_admin.","solutions":["Run deletions with the proxy admin master key","Keep the admin credential in a secret manager and restrict which jobs can use it","If teams must self-serve deletion, front it with an internal service holding the admin key plus your own approval flow","Check the key's user role (/user/info or the key record) if you are unsure why it is rejected"],"exampleFix":"# before (403: team admin key)\nhttpx.post(base + '/project/delete', headers=team_admin_hdr, json={'project_ids': ['p1']})\n\n# after: proxy admin master key\nhttpx.post(base + '/project/delete', headers=proxy_admin_hdr, json={'project_ids': ['p1']})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    r = httpx.post(base + '/project/delete', headers=hdr, json={'project_ids': ids})\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 403 and 'Only admins can delete' in e.response.text:\n        raise PermissionError('project deletion is proxy-admin-only; rerun with the admin master key') from None\n    raise","preventionTips":["Bind delete operations to the admin credential stored in a secret manager","Do not assume team admins can delete — creation and updates are allowed, deletion is not","Route team-initiated deletions through an approval service that uses the admin key"],"tags":["litellm","rbac","http-403","projects","admin-only"],"backgroundTag":"insufficient-permissions","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}