BerriAI/litellm · error · HTTPException

Only proxy admins, team admins, or org admins can call {rout

Error message

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}

What it means

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.

Source

Thrown at litellm/proxy/management_endpoints/key_management_endpoints.py:6176

            status_code=404,
            detail={"error": f"Key not found: {hashed_token}"},
        )

    # If the key belongs to a team, check team admin / org admin
    if target_key_row.team_id:
        team_obj: Final = await get_team_object(
            team_id=target_key_row.team_id,
            prisma_client=prisma_client,
            user_api_key_cache=user_api_key_cache,
            check_db_only=True,
        )
        if team_obj is not None:
            if _is_user_team_admin(user_api_key_dict=user_api_key_dict, team_obj=team_obj):
                return
            if await _is_user_org_admin_for_team(user_api_key_dict=user_api_key_dict, team_obj=team_obj):
                return

    raise HTTPException(
        status_code=403,
        detail={
            "error": f"Only proxy admins, team admins, or org admins can call {route}. "
            f"user_role={user_api_key_dict.user_role}, user_id={user_api_key_dict.user_id}"
        },
    )


@router.post("/key/block", tags=["key management"], dependencies=[Depends(user_api_key_auth)])
@management_endpoint_wrapper
async def block_key(
    data: BlockKeyRequest,
    http_request: Request,
    user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
    litellm_changed_by: str | None = Header(
        None,
        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",
    ),

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Run the call with the proxy admin's key (the LITELLM_MASTER_KEY or a key whose user_role is proxy_admin)
  2. 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
  3. For organization-wide administration, grant the caller the org admin role on the organization that owns the team
  4. 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

Example fix

# before
headers = {'Authorization': f'Bearer {team_member_key}'}   # 403: Only proxy admins, team admins, or org admins can call /key/block
# after
headers = {'Authorization': f'Bearer {os.environ["LITELLM_MASTER_KEY"]}'}
await client.post('/key/block', headers=headers, json={'key': hashed_token})
Defensive patterns

Strategy: try-catch

Try / catch

try:
    await client.post('/key/block', headers=headers, json={'key': tok})
except httpx.HTTPStatusError as e:
    if e.response.status_code == 403:
        detail = e.response.json().get('detail', {}).get('error', '')
        # detail contains user_role=/user_id= — use it to report which principal lacked rights
        raise PermissionError(f'insufficient role: {detail}')
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/50dcc13620ace605. Report an issue: GitHub.