alibaba/nacos · warning · IllegalArgumentException

role 'ROLE_ADMIN' is not permitted to create!

Error message

role 'ROLE_ADMIN' is not permitted to create!

What it means

Thrown by addRole when the requested role name equals AuthConstants.GLOBAL_ADMIN_ROLE ("ROLE_ADMIN"). Nacos reserves the global administrator role: it can only be granted through the dedicated addAdminRole(username) path, which also tracks single-admin existence, so the generic addRole refuses it. This guard prevents creating duplicate or untracked admin grants.

Solutions

  1. To grant admin privileges, use roleService.addAdminRole(username) instead of addRole.
  2. If seeding roles programmatically, skip any role name equal to AuthConstants.GLOBAL_ADMIN_ROLE ("ROLE_ADMIN").
  3. Filter the incoming role name list against reserved role names before calling addRole.

Example fix

// before
roleService.addRole("ROLE_ADMIN", username); // rejected

// after
roleService.addAdminRole(username);
Defensive patterns

Strategy: validation

Validate before calling

// Never pass ROLE_ADMIN to addRole; use addAdminRole.
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
    roleService.addAdminRole(username);
} else {
    roleService.addRole(role, username);
}

Prevention

When it happens

Trigger: Calling addRole("ROLE_ADMIN", username) directly; passing a role name read from config/UI that happens to equal ROLE_ADMIN; programmatically seeding roles from a list that includes the admin role.

Common situations: Automated bootstrap scripts that blindly insert every role including ROLE_ADMIN; UI forms that let users type the role name freely; migrating role sets from another system without filtering reserved names.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/0ecdca21b28147ba. Report an issue: GitHub.

Appendix: source

Thrown at plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/NacosRoleServiceDirectImpl.java:130

    
    @Override
    public Page<PermissionInfo> getPermissions(String role, int pageNo, int pageSize) {
        Page<PermissionInfo> pageInfo =
            permissionPersistService.getPermissions(role, pageNo, pageSize);
        if (pageInfo == null) {
            return new Page<>();
        }
        return pageInfo;
    }
    
    @Override
    public void addRole(String role, String username) {
        if (userDetailsService.getUser(username) == null) {
            throw new IllegalArgumentException("user '" + username + "' not found!");
        }
        
        if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
            throw new IllegalArgumentException(
                "role '" + AuthConstants.GLOBAL_ADMIN_ROLE + "' is not permitted to create!");
        }
        
        if (AuthConstants.ANONYMOUS_ROLE.equals(role)) {
            throw new IllegalArgumentException(
                "role '" + AuthConstants.ANONYMOUS_ROLE + "' is reserved by the system");
        }
        
        if (isUserBoundToRole(role, username)) {
            throw new IllegalArgumentException(
                "user '" + username + "' already bound to the role '" + role + "'!");
        }
        
        rolePersistService.addRole(role, username);
        getCachedRoleSet().add(role);
        invalidateUserRoles(username);
    }
    

View on GitHub (pinned to 9b989acdf1)