{"record":{"id":"4e475d6a14738e73","repo":"alibaba/nacos","slug":"role-role-admin-is-not-permitted-to-delete","errorCode":null,"errorMessage":"role 'ROLE_ADMIN' is not permitted to delete!","messagePattern":"role 'ROLE_ADMIN' is not permitted to delete!","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/AbstractCheckedRoleService.java","lineNumber":148,"sourceCode":"        this.hasGlobalAdminRole = hasGlobalAdminRole;\n        return hasGlobalAdminRole;\n    }\n    \n    /**\n     * Mark the local global-admin lookup cache after an administrator role is created.\n     */\n    protected void markGlobalAdminRolePresent() {\n        hasGlobalAdminRole = true;\n    }\n    \n    /**\n     * Reject deletion or manual creation of system-reserved roles.\n     *\n     * @param role role name to check\n     */\n    protected void rejectReservedRole(String role) {\n        if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.GLOBAL_ADMIN_ROLE + \"' is not permitted to delete!\");\n        }\n        if (AuthConstants.ANONYMOUS_ROLE.equals(role)) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.ANONYMOUS_ROLE + \"' is reserved by the system\");\n        }\n    }\n    \n    /**\n     * If API is update user password, don't do permission check, because there is permission check in API logic.\n     */\n    private boolean isUpdatePasswordPermission(Permission permission) {\n        Properties properties = permission.getResource().getProperties();\n        return null != properties && properties.contains(AuthConstants.UPDATE_PASSWORD_ENTRY_POINT);\n    }\n    \n    private String joinResource(Resource resource) {\n        if (SignType.SPECIFIED.equals(resource.getType())) {","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/AbstractCheckedRoleService.java#L130-L166","documentation":"Thrown by AbstractCheckedRoleService.rejectReservedRole when an attempt is made to delete (or in some paths, manually create) the ROLE_ADMIN role. Nacos designates GLOBAL_ADMIN_ROLE (ROLE_ADMIN) as a system-reserved role that cannot be removed through the API. The rejectReservedRole method is called by role deletion and creation flows to enforce this invariant.","triggerScenarios":"An admin API call (e.g., DELETE /v3/admin/auth/roles?role=ROLE_ADMIN) targets the global admin role. The rejectReservedRole guard intercepts this before the deletion reaches the persistence layer. Also triggered if a role-creation flow attempts to create a role with this reserved name when it already exists.","commonSituations":"Automated cleanup script tries to remove all roles including system ones; a migration or reset tooling attempts to delete and recreate admin roles; an admin mistakenly attempts to delete the built-in admin role via the console UI or API.","solutions":["Do not attempt to delete ROLE_ADMIN — it is required by the system for administrative access.","If you need to reset admin access, change the admin user's password or recreate the user, not the role.","Filter system-reserved roles out of any automated cleanup or migration scripts.","If building a role management UI, disable the delete button for system-reserved roles."],"exampleFix":"// before\nroleService.deleteRole(\"ROLE_ADMIN\"); // throws IllegalArgumentException\n\n// after\nif (!AuthConstants.GLOBAL_ADMIN_ROLE.equals(role) && !AuthConstants.ANONYMOUS_ROLE.equals(role)) {\n    roleService.deleteRole(role);\n} else {\n    return Result.failed(\"Cannot delete system-reserved role: \" + role);\n}","handlingStrategy":"validation","validationCode":"// Check for reserved role before attempting deletion\nSet<String> reservedRoles = Set.of(\n    AuthConstants.GLOBAL_ADMIN_ROLE,\n    AuthConstants.ANONYMOUS_ROLE\n);\nif (reservedRoles.contains(roleName)) {\n    throw new IllegalArgumentException(\"Cannot delete system-reserved role: \" + roleName);\n}\nroleService.deleteRole(roleName);","typeGuard":"public static boolean isReservedRole(String role) {\n    return AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)\n        || AuthConstants.ANONYMOUS_ROLE.equals(role);\n}","tryCatchPattern":"try {\n    roleService.deleteRole(roleName);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"not permitted to delete\")) {\n        return Result.failed(\"Role '\" + roleName + \"' is system-reserved and cannot be deleted\");\n    }\n    throw e;\n}","preventionTips":["Maintain a deny-list of reserved role names (ROLE_ADMIN, __nacos_anonymous_role__) in role management tooling.","Filter system roles out of batch deletion or migration scripts.","Disable delete actions for system-reserved roles in admin UIs.","Document which roles are system-reserved for API consumers."],"tags":["auth-plugin","role-management","reserved-role","admin","input-validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}