alibaba/nacos · warning · IllegalArgumentException

role '__nacos_anonymous_role__' is reserved by the system

Error message

role '__nacos_anonymous_role__' is reserved by the system

What it means

Thrown by the remote addRole when the role name equals ANONYMOUS_ROLE ("__nacos_anonymous_role__"). Mirrors the direct impl guard: the anonymous role is system-managed and cannot be created through the public API. The check is local on the console node, so no remote request is issued.

Source

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

            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,
                unpectedException.getMessage());
        }
    }
    

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Exclude __nacos_anonymous_role__ from role lists fed to addRole.
  2. Manage anonymous access via authorization configuration, not role creation.
  3. Add a reserved-name blocklist in your provisioning code.

Example fix

// before
roles.forEach(r -> roleService.addRole(r, username)); // fails on anonymous

// after
Set<String> reserved = Set.of("ROLE_ADMIN", "__nacos_anonymous_role__");
roles.stream().filter(r -> !reserved.contains(r))
     .forEach(r -> roleService.addRole(r, username));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> reserved = Set.of(AuthConstants.GLOBAL_ADMIN_ROLE, AuthConstants.ANONYMOUS_ROLE);
if (!reserved.contains(role)) {
    roleService.addRole(role, username);
}

Prevention

When it happens

Trigger: Console-side addRole("__nacos_anonymous_role__", username); importing a role set containing the anonymous role via the remote path.

Common situations: Bulk role import without reserved-name filtering; misconfigured sync job replaying default roles.

Related errors


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