BerriAI/litellm · error · HTTPException

Only admins or team admins can create projects. Your role is

Error message

Only admins or team admins can create projects. Your role is {user_api_key_dict.user_role}

What it means

POST /project/new authorizes via _check_user_permission_for_project: only proxy admins or admins of the specific target team may create projects for it. If the caller's role/team membership does not satisfy this, the proxy returns HTTP 403 including the caller's actual role. This prevents a team admin from creating projects under another team's namespace.

Source

Thrown at enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py:387

        team_object = await _validate_team_exists(team_id=data.team_id, prisma_client=prisma_client)

        # Validate project limits against team limits
        _check_team_project_limits(
            team_object=LiteLLM_TeamTable.model_validate(team_object.model_dump()),
            data=data,
        )

        # Check if user has permission to create projects for this team
        # only team admins can create projects for their team
        has_permission = await _check_user_permission_for_project(
            user_api_key_dict=user_api_key_dict,
            team_id=data.team_id,
            prisma_client=prisma_client,
            team_object=LiteLLM_TeamTable.model_validate(team_object.model_dump()),
        )

        if not has_permission:
            raise HTTPException(
                status_code=403,
                detail={
                    "error": f"Only admins or team admins can create projects. Your role is {user_api_key_dict.user_role}"
                },
            )

        # Generate project_id if not provided
        if data.project_id is None:
            data.project_id = str(uuid.uuid4())
        else:
            # Check if project_id already exists
            existing_project = await prisma_client.db.litellm_projecttable.find_unique(
                where={"project_id": data.project_id}
            )
            if existing_project is not None:
                raise ProxyException(
                    message=f"Project id = {data.project_id} already exists. Please use a different project id.",
                    type="bad_request",

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Have a proxy admin or the target team's admin perform the creation (or use an admin key)
  2. Add the user as an admin of the team (PUT /team/update with the user in team_admin list / admin role) and retry
  3. If the caller should be a proxy admin, issue the key from an admin user or use the master key

Example fix

# before (member-level key)
curl -H 'Authorization: Bearer sk-member-key' -X POST .../project/new -d '{"team_id":"t1",...}'
# after (admin key)
curl -H 'Authorization: Bearer sk-admin-key' -X POST .../project/new -d '{"team_id":"t1",...}'
Defensive patterns

Strategy: validation

Validate before calling

# Verify caller's role/team-admin status before attempting creation
me = await client.get('/user/info')
if not me.user_info.get('user_role') in ('proxy_admin', 'proxy_admin_viewer'):
    team = await client.get(f'/team/info?team_id={team_id}')
    admins = [m['user_id'] for m in (team.teams[0].members_with_roles or []) if m.get('role') == 'admin']
    if me.user_id not in admins:
        raise PermissionError('Caller cannot create projects for this team')

Type guard

const canCreateProject = (userRole, userId, team) =>
  userRole === 'proxy_admin' ||
  (team.members_with_roles ?? []).some(
    (m) => m.user_id === userId && m.role === 'admin'
  );

Try / catch

catch (e) {
  if (e.status === 403 && /Only admins or team admins can create projects/.test(e.body?.detail?.error ?? '')) {
    throw new Error(`Permission denied (role=${myRole}); ask a proxy/team admin to create the project`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling POST /project/new with a virtual key whose user is a member (not admin) of data.team_id, or an internal-user key with no team affiliation, e.g. role 'internal_user' targeting a team they do not administer.

Common situations: A team member with an own-api-key trying to self-provision a project, service accounts without admin grants, or an org_admin key targeting a team outside their scope.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/feb68cbd01a558e4. Report an issue: GitHub.