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
- To grant admin privileges, use roleService.addAdminRole(username) instead of addRole.
- If seeding roles programmatically, skip any role name equal to AuthConstants.GLOBAL_ADMIN_ROLE ("ROLE_ADMIN").
- 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
- Treat ROLE_ADMIN as a reserved name in all role-provisioning code.
- Route admin grants exclusively through addAdminRole.
- Filter reserved role names from imported role catalogs.
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
- role '__nacos_anonymous_role__' is reserved by the system
- role 'ROLE_ADMIN' is not permitted to create!
- user '{username}' not found!
- role 'ROLE_ADMIN' already exist !
- role {role} not found!
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/0ecdca21b28147ba.
Report an issue: GitHub.