{"record":{"id":"0bcfda37211a292e","repo":"BerriAI/litellm","slug":"user-change-initiated-by-user-id-is-not-a-proxy","errorCode":null,"errorMessage":"User={change_initiated_by.user_id} is not a Proxy Admin or Team Admin for team={team.team_id}. Please ask your Proxy Admin to allow this action under 'Member Permissions' for this team.","messagePattern":"User=(.+?) is not a Proxy Admin or Team Admin for team=(.+?)\\. Please ask your Proxy Admin to allow this action under 'Member Permissions' for this team\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":3346,"sourceCode":"                detail=f\"User={key.user_id} is not a member of the team={team.team_id}. Check team members via `/team/info`.\",\n            )\n\n    # Check if the person initiating the change is a Proxy Admin or Team Admin\n    if (\n        change_initiated_by.user_role == LitellmUserRoles.PROXY_ADMIN.value\n        or _is_user_team_admin(\n            user_api_key_dict=change_initiated_by,\n            team_obj=team,\n        )\n        or TeamMemberPermissionChecks.does_team_member_have_permissions_for_endpoint(\n            team_member_object=member_object,\n            team_table=cast(LiteLLM_TeamTableCachedObj, team),\n            route=KeyManagementRoutes.KEY_UPDATE.value,\n        )\n    ):\n        return\n    else:\n        raise HTTPException(\n            status_code=403,\n            detail=f\"User={change_initiated_by.user_id} is not a Proxy Admin or Team Admin for team={team.team_id}. Please ask your Proxy Admin to allow this action under 'Member Permissions' for this team.\",\n        )\n\n\n@router.post(\"/key/delete\", tags=[\"key management\"], dependencies=[Depends(user_api_key_auth)])\n@management_endpoint_wrapper\nasync def delete_key_fn(\n    data: KeyRequest,\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    ),\n):\n    \"\"\"\n    Delete a key from the key management system.\n","sourceCodeStart":3328,"sourceCodeEnd":3364,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L3328-L3364","documentation":"LiteLLM only lets a team-scoped key change be initiated by a Proxy Admin, a Team Admin of that team, or a member who was explicitly granted the KEY_UPDATE permission under the team's Member Permissions. The change_initiated_by identity (derived from the calling virtual key / user) failed all three checks, so the 403 explains both who was rejected and the remediation path (Member Permissions).","triggerScenarios":"A plain internal-user key calling POST /key/update (or /team/key/bulk_update) on a key belonging to a team where the caller is only a 'user' role member; a new admin using a personal key before being made team_admin.","commonSituations":"Delegating key rotation to a team member without granting member permissions; a service account key (not bound to an admin user) attempting team key updates; admin left the org and their replacement's key lacks roles.","solutions":["Have a Proxy Admin (master key) perform the key update instead.","Or add the caller as team_admin: POST /team/member_add with role team_admin (or /team/update changing the member's role).","Or grant the KEY_UPDATE member permission for the team: PATCH /team/{team_id}/member/permissions (Enterprise UI: Team Settings -> Member Permissions)."],"exampleFix":"# before (internal-user key)\nclient.headers[\"Authorization\"] = \"Bearer sk-user-key\"\nclient.post(\"/key/update\", json={\"key\": \"sk-target\", \"metadata\": {...}})\n\n# after (proxy admin master key)\nclient.headers[\"Authorization\"] = \"Bearer sk-master\"\nclient.post(\"/key/update\", json={\"key\": \"sk-target\", \"metadata\": {...}})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    client.post(\"/key/update\", json={\"key\": target_key, ...})\nexcept HTTPError as e:\n    if e.response.status_code == 403 and \"not a Proxy Admin or Team Admin\" in e.response.text:\n        escalate_to_proxy_admin(target_key)  # or use master-key credential\n    else:\n        raise","preventionTips":["Run key-management automation with a dedicated proxy-admin service key, not user keys.","Document which identities may rotate keys per team; keep the list in code, not tribal memory.","When delegating, grant the KEY_UPDATE member permission explicitly rather than handing out admin keys."],"tags":["authorization","rbac","admin-permissions","key-management","litellm-proxy"],"backgroundTag":"permission-denied-403","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}