alibaba/nacos · error · IllegalArgumentException
cannot delete admin: + username
Error message
cannot delete admin: + username
What it means
Thrown by UserControllerV3.deleteUser as IllegalArgumentException when the target user holds the GLOBAL_ADMIN role. The DELETE user endpoint enumerates the user's roles and refuses to remove any user whose roles include the global admin role, to prevent locking the cluster out.
Solutions
- First revoke or reassign the GLOBAL_ADMIN role from the user (via the role API), then delete.
- If you intend to remove the last admin, demote carefully and ensure another admin remains to avoid lockout.
- Audit roleInfoList for the user before issuing delete to fail fast in the client.
Example fix
// before
roleService.getRoles(username).forEach(r -> { /* ignore */ });
userDetailsService.deleteUser(username); // throws if admin
// after: strip admin role first
for (RoleInfo r : roleService.getRoles(username)) {
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(r.getRole())) {
roleService.deleteRole(username, r.getRole());
}
}
userDetailsService.deleteUser(username); Defensive patterns
Strategy: validation
Validate before calling
boolean isGlobalAdmin(List<RoleInfo> roles) {
return roles != null && roles.stream()
.anyMatch(r -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(r.getRole()));
}
// guard before delete: if (isGlobalAdmin(roleService.getRoles(username))) reject; Type guard
static boolean canDeleteUser(NacosRoleService rs, String username) {
List<RoleInfo> roles = rs.getRoles(username);
return roles == null || roles.stream()
.noneMatch(r -> AuthConstants.GLOBAL_ADMIN_ROLE.equals(r.getRole()));
} Try / catch
try {
userDetailsService.deleteUser(username);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("cannot delete admin")) {
// strip admin role first, then retry
} else throw e;
} Prevention
- Audit the user's roles before issuing delete.
- Strip GLOBAL_ADMIN_ROLE before deleting promoted users.
- Never let cleanup scripts delete the last admin.
When it happens
Trigger: DELETE /v3/admin/.../users?username=X where X is assigned the GLOBAL_ADMIN role. Triggered by admin-user deletion attempts via console or API.
Common situations: Attempting to delete the primary admin; deleting a user that was promoted to admin for operational reasons; cleanup scripts that do not account for admin role membership.
Related errors
- user ' + username + ' already exist!
- user + username + not exist!
- Plugin config value cannot be null
- Plugin config value is not a boolean
- Plugin config value is not a number
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/aac02d07bffa4b89.
Report an issue: GitHub.
Appendix: source
Thrown at plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/controller/v3/UserControllerV3.java:164
}
/**
* Delete an existed user.
*
* @param username username of user
* @return ok if deleted succeed, keep silent if user not exist
* @since 1.2.0
*/
@Since("3.0.0")
@DeleteMapping
@Secured(resource = AuthConstants.CONSOLE_RESOURCE_NAME_PREFIX + "users",
action = ActionTypes.WRITE, apiType = ApiType.ADMIN_API)
public Result<String> deleteUser(@RequestParam String username) {
List<RoleInfo> roleInfoList = roleService.getRoles(username);
if (roleInfoList != null) {
for (RoleInfo roleInfo : roleInfoList) {
if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(roleInfo.getRole())) {
throw new IllegalArgumentException("cannot delete admin: " + username);
}
}
}
userDetailsService.deleteUser(username);
return Result.success("delete user ok!");
}
/**
* Update an user.
*
* @param username username of user
* @param newPassword new password of user
* @param response http response
* @param request http request
* @return ok if update succeed
* @throws IllegalArgumentException if user not exist or oldPassword is incorrect
* @since 1.2.0
*/View on GitHub (pinned to 9b989acdf1)