theonedev/onedev · error · ExplicitException
Root user cannot be deleted
Error message
Root user cannot be deleted
What it means
OneDev refuses to delete the root (built-in administrator) user via the REST deleteUser endpoint. The root account is a system bootstrap account and must always exist; deleting it would leave the instance potentially unadministrable. The DELETE call throws ExplicitException before userService.delete is invoked.
Source
Thrown at server-core/src/main/java/io/onedev/server/rest/resource/UserResource.java:628
if (!getAuthUser().equals(user)) {
var newAuditContent = VersionedXmlDoc.fromBean(sshKey).toXML();
auditService.audit(null, "added ssh key to account \"" + user.getName() + "\" via RESTful API", null, newAuditContent);
}
return sshKey.getId();
}
@Api(order=2300)
@Path("/{userId}")
@DELETE
public Response deleteUser(@PathParam("userId") Long userId) {
if (!SecurityUtils.isAdministrator())
throw new UnauthorizedException();
User user = userService.load(userId);
if (user.isRoot())
throw new ExplicitException("Root user cannot be deleted");
else if (user.equals(getAuthUser()))
throw new ExplicitException("Cannot delete yourself");
else
userService.delete(user);
var oldAuditContent = VersionedXmlDoc.fromBean(getData(user)).toXML();
auditService.audit(null, "deleted account \"" + user.getName() + "\" via RESTful API", oldAuditContent, null);
return Response.ok().build();
}
public static class UserData implements Serializable {
private static final long serialVersionUID = 1L;
@Api(order=5, description="ID of the user")
private Long id;
View on GitHub (pinned to d44925c47c)
Solutions
- Exclude the root user from deletion lists (skip users where isRoot is true)
- If the root account needs to be locked down, rename it or disable password login instead of deleting
- Never iterate 'delete all users' against an OneDev instance without filtering
Example fix
// before
for (long id : userIds) deleteUser(id);
// after
for (long id : userIds) { User u = getUser(id); if (!u.isRoot()) deleteUser(id); } Defensive patterns
Strategy: validation
Validate before calling
User u = getUser(userId); if (u.isRoot()) throw new SkipException("refusing to delete root"); Type guard
boolean isDeletable(User u) { return u != null && !u.isRoot(); } Try / catch
try { deleteUser(userId); } catch (ExplicitException e) { log.warn("delete rejected: {}", e.getMessage()); } Prevention
- Always exclude the root account from deletion lists
- Use userId, not name matching, to identify the root account
- Review bulk-cleanup scripts for unfiltered 'delete all' logic
When it happens
Trigger: Calling DELETE /users/{userId} with the id of the root user (User.isRoot()==true) as an administrator.
Common situations: Bulk user-cleanup scripts that don't exclude the root account; attempting to 'reset' an instance by deleting all users including root.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Should only enable normal users
- Should only convert normal users to service accounts
- Cannot set queries and watches for disabled user
- Cannot set queries and watches for service or ai account
- Cannot delete yourself
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/19e48431aaa54f39.
Report an issue: GitHub.