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.

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)

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.