{"record":{"id":"feb68cbd01a558e4","repo":"BerriAI/litellm","slug":"only-admins-or-team-admins-can-create-projects-yo","errorCode":null,"errorMessage":"Only admins or team admins can create projects. Your role is {user_api_key_dict.user_role}","messagePattern":"Only admins or team admins can create projects\\. Your role is (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py","lineNumber":412,"sourceCode":"        team_object = await _validate_team_exists(team_id=data.team_id, prisma_client=prisma_client)\n\n        # Validate project limits against team limits\n        _check_team_project_limits(\n            team_object=LiteLLM_TeamTable.model_validate(team_object.model_dump()),\n            data=data,\n        )\n\n        # Check if user has permission to create projects for this team\n        # only team admins can create projects for their team\n        has_permission = await _check_user_permission_for_project(\n            user_api_key_dict=user_api_key_dict,\n            team_id=data.team_id,\n            prisma_client=prisma_client,\n            team_object=LiteLLM_TeamTable.model_validate(team_object.model_dump()),\n        )\n\n        if not has_permission:\n            raise HTTPException(\n                status_code=403,\n                detail={\n                    \"error\": f\"Only admins or team admins can create projects. Your role is {user_api_key_dict.user_role}\"\n                },\n            )\n\n        # Generate project_id if not provided\n        if data.project_id is None:\n            data.project_id = str(uuid.uuid4())\n        else:\n            # Check if project_id already exists\n            existing_project = await _project_table(prisma_client).find_unique(where={\"project_id\": data.project_id})\n            if existing_project is not None:\n                raise ProxyException(\n                    message=f\"Project id = {data.project_id} already exists. Please use a different project id.\",\n                    type=\"bad_request\",\n                    code=400,\n                    param=\"project_id\",","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py#L394-L430","documentation":"Project creation is restricted to proxy admins or admins of the target team. _check_user_permission_for_project resolves the caller from the virtual key and passes only for proxy-admin roles or users listed with an admin role in the team's members_with_roles. On failure the endpoint returns 403 and echoes the caller's user_role so you can see exactly why the check failed.","triggerScenarios":"POST /project/new where data.team_id names a team whose members_with_roles does not include the key's user as an admin, or where the key maps to a non-admin user (e.g. user_role internal_user or app_user).","commonSituations":"Automating project setup with a team-member or service key; platform-team-owned teams that other teams try to create projects under; SSO role mapping that assigns internal_user to the caller, which never passes this check.","solutions":["Retry with the proxy admin master key","Add the caller's user_id to the team as an admin first (POST /team/update with members_with_roles containing an admin entry for that user), then retry","Inspect the role echoed in the message: internal_user/app_user means the key belongs to a non-admin account — issue the key from an admin user instead","Double-check data.team_id: being admin of team A grants no rights to create projects under team B"],"exampleFix":"# before (403 with team-member key)\nhttpx.post(base + '/project/new', headers=team_member_hdr, json={'team_id': 'team-a', 'project_name': 'billing'})\n\n# after: make the user an admin of the team, then create\nhttpx.post(base + '/team/update', headers=admin_hdr, json={'team_id': 'team-a', 'members_with_roles': [{'role': 'admin', 'user_id': 'user-123'}]})\nhttpx.post(base + '/project/new', headers=user_123_hdr, json={'team_id': 'team-a', 'project_name': 'billing'})","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    r = httpx.post(base + '/project/new', headers=hdr, json=payload)\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 403 and 'Only admins or team admins' in e.response.text:\n        role = extract_role(e.response.text)  # message echoes user_role\n        raise PermissionError(f'caller role {role} cannot create projects for team {payload[\"team_id\"]}; use an admin of that team') from None\n    raise","preventionTips":["Drive project provisioning with the proxy admin key","Maintain an explicit map of which users hold admin roles in each team (members_with_roles)","Test permission-dependent automation with a non-admin key before shipping"],"tags":["litellm","rbac","http-403","teams","projects"],"backgroundTag":"insufficient-permissions","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}