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 NacosRoleServiceRemoteImpl.addRole (the remote/console path) when the role name equals GLOBAL_ADMIN_ROLE ("ROLE_ADMIN"). Identical guard to the direct impl: the admin role must be granted via addAdminRole, never via the generic role-add. The check is local to the console node before it even forwards the request, so no remote call is made.

Solutions

  1. Use roleService.addAdminRole(username) to grant admin privileges.
  2. Filter ROLE_ADMIN out of any role list passed to addRole.
  3. Treat reserved role names as non-creatable in your provisioning logic.

Example fix

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

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

Strategy: validation

Validate before calling

if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {
    roleService.addAdminRole(username);
} else {
    roleService.addRole(role, username);
}

Prevention

When it happens

Trigger: Console-side addRole("ROLE_ADMIN", username); seeding roles from a catalog that includes the admin role via the remote impl.

Common situations: Console deployment forwarding auth ops attempting to create the admin role through the wrong endpoint; automation that does not filter reserved names.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/95b9d19b06c91e30. 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/NacosRoleServiceRemoteImpl.java:170

            return result.getData();
        } catch (NacosException e) {
            throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
        } catch (Exception unpectedException) {
            throw new NacosRuntimeException(NacosException.SERVER_ERROR,
                unpectedException.getMessage());
        }
    }
    
    @Override
    public List<RoleInfo> getAllRoles() {
        return getRoles(StringUtils.EMPTY, StringUtils.EMPTY, DEFAULT_PAGE_NO, Integer.MAX_VALUE)
            .getPageItems();
    }
    
    @Override
    public void addRole(String role, String username) {
        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");
        }
        Map<String, String> body = Map.of("role", role, "username", username);
        try {
            HttpRestResult<String> httpResult = nacosRestTemplate.postForm(
                buildRemoteRoleUrlPath(AuthConstants.ROLE_PATH),
                RemoteServerUtil.buildServerRemoteHeader(), body, String.class);
            RemoteServerUtil.singleCheckResult(httpResult);
            getCachedRoleSet().add(role);
            invalidateUserRoles(username);
        } catch (NacosException e) {
            throw new NacosRuntimeException(e.getErrCode(), e.getErrMsg());
        } catch (Exception unpectedException) {
            throw new NacosRuntimeException(NacosException.SERVER_ERROR,

View on GitHub (pinned to 9b989acdf1)