{"record":{"id":"c83bb431c9eacdcd","repo":"BerriAI/litellm","slug":"only-proxy-admin-or-org-admin-users-may-delete-use","errorCode":null,"errorMessage":"Only PROXY_ADMIN or ORG_ADMIN users may delete users.","messagePattern":"Only PROXY_ADMIN or ORG_ADMIN users may delete users\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"litellm/proxy/management_endpoints/internal_user_endpoints.py","lineNumber":2257,"sourceCode":"    # cross-check data.user_ids against the caller's scope, so without this\n    # loop an org-admin of org-A could delete users in org-B by supplying\n    # {\"user_ids\": [victim_in_org_B], \"organization_id\": \"org-A\"}.\n    caller_is_proxy_admin: Final = user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value\n    caller_admin_org_ids: set = set()\n    if not caller_is_proxy_admin:\n        caller_memberships: Final = (\n            await _organization_membership_table(prisma_client).find_many(\n                where={\n                    \"user_id\": user_api_key_dict.user_id,\n                    \"user_role\": LitellmUserRoles.ORG_ADMIN.value,\n                }\n            )\n            if user_api_key_dict.user_id\n            else []\n        )\n        caller_admin_org_ids = {m.organization_id for m in caller_memberships if m.organization_id}\n        if not caller_admin_org_ids:\n            raise HTTPException(\n                status_code=403,\n                detail={\"error\": \"Only PROXY_ADMIN or ORG_ADMIN users may delete users.\"},\n            )\n\n    # Batch-fetch target memberships once before the per-user loop. Avoids\n    # an N+1 DB call when delete_user is called with a large user_ids list.\n    target_org_ids_by_user: Final[dict[str, set]] = {}\n    if not caller_is_proxy_admin:\n        all_target_memberships: Final = await _organization_membership_table(prisma_client).find_many(\n            where={\"user_id\": {\"in\": data.user_ids}}\n        )\n        for m in all_target_memberships:\n            if not m.organization_id:\n                continue\n            target_org_ids_by_user.setdefault(m.user_id, set()).add(m.organization_id)\n\n    # check that all teams passed exist\n    for user_id in data.user_ids:","sourceCodeStart":2239,"sourceCodeEnd":2275,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/internal_user_endpoints.py#L2239-L2275","documentation":"Error \"Only PROXY_ADMIN or ORG_ADMIN users may delete users.\" thrown in BerriAI/litellm.","triggerScenarios":"Thrown at litellm/proxy/management_endpoints/internal_user_endpoints.py:2257 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Authenticate with a PROXY_ADMIN or ORG_ADMIN key to delete users.","Ask an admin to perform the deletion on your behalf."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}