{"record":{"id":"a2daedd5a4e87c19","repo":"apolloconfig/apollo","slug":"create-cluster-permission-is-required","errorCode":null,"errorMessage":"Create cluster permission is required","messagePattern":"Create cluster permission is required","errorType":"exception","errorClass":"AccessDeniedException","httpStatus":403,"severity":"error","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ClusterController.java","lineNumber":142,"sourceCode":"        return;\n      }\n      throw new AccessDeniedException(\"Super admin permission is required\");\n    }\n    throw new AccessDeniedException(\"Access is denied\");\n  }\n\n  private void requireReadApplicationPermissionForUserToken(String appId) {\n    if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())\n        && !unifiedPermissionValidator.hasReadApplicationPermission(appId)) {\n      throw new AccessDeniedException(\"Access is denied\");\n    }\n  }\n\n  private void requireCreateClusterPermissionForUserToken(String appId, String env,\n      String clusterName) {\n    if (UserIdentityConstants.USER_TOKEN.equals(UserIdentityContextHolder.getAuthType())\n        && !unifiedPermissionValidator.hasCreateClusterPermission(appId, env, clusterName)) {\n      throw new AccessDeniedException(\"Create cluster permission is required\");\n    }\n  }\n\n  private String resolveOperator(String operator) {\n    String authType = UserIdentityContextHolder.getAuthType();\n    if (UserIdentityConstants.USER.equals(authType)\n        || UserIdentityConstants.USER_TOKEN.equals(authType)) {\n      UserInfo loginUser = userInfoHolder.getUser();\n      if (loginUser == null || StringUtils.isBlank(loginUser.getUserId())) {\n        throw new BadRequestException(\"Current user not found\");\n      }\n      return loginUser.getUserId();\n    }\n\n    RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(operator),\n        \"operator should not be null or empty\");\n\n    if (userService.findByUserId(operator) == null) {","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ClusterController.java#L124-L160","documentation":"Thrown by ClusterController.requireCreateClusterPermissionForUserToken when a USER_TOKEN identity lacks the cluster:create operation scope for the target appId/env/clusterName combination. The check delegates to unifiedPermissionValidator.hasCreateClusterPermission(appId, env, clusterName), which for USER_TOKEN calls userTokenPermissionValidator.hasCreateClusterPermission. Maps to HTTP 403 AccessDeniedException.","triggerScenarios":"POST /openapi/v1/envs/{env}/apps/{appId}/clusters with a USER_TOKEN that does not have the cluster:create operation (UserTokenOperation.CLUSTER_CREATE = \"cluster:create\") granted for the target appId.","commonSituations":"A developer generates a personal access token for CI/CD but only grants config:read and config:modify scopes, forgetting to add cluster:create. The token can manage items but cannot create new clusters.","solutions":["Add the cluster:create operation scope to the USER_TOKEN's grants in the Portal token management page.","If the token is scoped per-app, ensure the specific appId is included in the token's resource-scoped operations.","Switch to a CONSUMER token with create-cluster permission if the operation is app-scoped automation."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before create-cluster with USER_TOKEN, verify cluster:create scope\nif (!tokenHasOperation(\"cluster:create\", appId)) {\n    throw new SecurityException(\"USER_TOKEN lacks cluster:create scope for appId: \" + appId);\n}","typeGuard":null,"tryCatchPattern":"try {\n    client.post(\"/openapi/v1/envs/\" + env + \"/apps/\" + appId + \"/clusters\", cluster);\n} catch (AccessDeniedException e) {\n    logger.error(\"USER_TOKEN lacks cluster:create for appId={}. Add scope in Portal.\", appId);\n    throw e;\n}","preventionTips":["When provisioning a USER_TOKEN for cluster management, include cluster:create in the scope.","Document the full list of operations a token needs for each automation scenario.","Test token scopes against a staging environment before production deployment."],"tags":["authorization","openapi","cluster","permissions","user-token","access-control","http-403"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}