{"record":{"id":"50dcc13620ace605","repo":"BerriAI/litellm","slug":"only-proxy-admins-team-admins-or-org-admins-can","errorCode":null,"errorMessage":"Only proxy admins, team admins, or org admins can call {route}. user_role={user_api_key_dict.user_role}, user_id={user_api_key_dict.user_id}","messagePattern":"Only proxy admins, team admins, or org admins can call (.+?)\\. user_role=(.+?), user_id=(.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":6176,"sourceCode":"            status_code=404,\n            detail={\"error\": f\"Key not found: {hashed_token}\"},\n        )\n\n    # If the key belongs to a team, check team admin / org admin\n    if target_key_row.team_id:\n        team_obj: Final = await get_team_object(\n            team_id=target_key_row.team_id,\n            prisma_client=prisma_client,\n            user_api_key_cache=user_api_key_cache,\n            check_db_only=True,\n        )\n        if team_obj is not None:\n            if _is_user_team_admin(user_api_key_dict=user_api_key_dict, team_obj=team_obj):\n                return\n            if await _is_user_org_admin_for_team(user_api_key_dict=user_api_key_dict, team_obj=team_obj):\n                return\n\n    raise HTTPException(\n        status_code=403,\n        detail={\n            \"error\": f\"Only proxy admins, team admins, or org admins can call {route}. \"\n            f\"user_role={user_api_key_dict.user_role}, user_id={user_api_key_dict.user_id}\"\n        },\n    )\n\n\n@router.post(\"/key/block\", tags=[\"key management\"], dependencies=[Depends(user_api_key_auth)])\n@management_endpoint_wrapper\nasync def block_key(\n    data: BlockKeyRequest,\n    http_request: Request,\n    user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),\n    litellm_changed_by: str | None = Header(\n        None,\n        description=\"The litellm-changed-by header enables tracking of actions performed by authorized users on behalf of other users, providing an audit trail for accountability\",\n    ),","sourceCodeStart":6158,"sourceCodeEnd":6194,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L6158-L6194","documentation":"The 403 authorization failure from _check_key_admin_access: the caller proved who they are but holds none of the roles allowed to administer the target key. The function allows proxy admins unconditionally, then (only if the key belongs to a team) team admins of that team and org admins of that team's organization; everyone else is rejected with the caller's role and id embedded in the detail for debugging.","triggerScenarios":"An internal user or regular team member POSTs /key/block or /key/unblock for someone else's key; a team admin of team A tries to block a key belonging to team B; a key has no team_id so the team/org-admin branch is skipped entirely and only proxy admins pass.","commonSituations":"Automation scripts authenticated with a normal user's virtual key instead of the proxy master key;自助 admin tooling where the operator was added to the org but not as org admin; keys created without a team that admins assumed were team-scoped.","solutions":["Run the call with the proxy admin's key (the LITELLM_MASTER_KEY or a key whose user_role is proxy_admin)","If the key is team-scoped, make the caller a team admin: add them via /team/member_add with user_role='admin' for that exact team","For organization-wide administration, grant the caller the org admin role on the organization that owns the team","Verify your assumptions with the user_role/user_id echoed in the error detail — a wrong key on the Authorization header is the most common cause"],"exampleFix":"# before\nheaders = {'Authorization': f'Bearer {team_member_key}'}   # 403: Only proxy admins, team admins, or org admins can call /key/block\n# after\nheaders = {'Authorization': f'Bearer {os.environ[\"LITELLM_MASTER_KEY\"]}'}\nawait client.post('/key/block', headers=headers, json={'key': hashed_token})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    await client.post('/key/block', headers=headers, json={'key': tok})\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 403:\n        detail = e.response.json().get('detail', {}).get('error', '')\n        # detail contains user_role=/user_id= — use it to report which principal lacked rights\n        raise PermissionError(f'insufficient role: {detail}')\n    raise","preventionTips":["Run key administration with the proxy master key or a proxy_admin user's key","For team-scoped automation, add the service account to the team with role 'admin' first","Parse user_role/user_id from the 403 detail to distinguish 'wrong key on the header' from 'genuinely missing grant'"],"tags":["authorization","forbidden","rbac","litellm-proxy","keys"],"backgroundTag":"insufficient-permissions","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}