RocketChat/Rocket.Chat · error · Meteor.Error
error-admin-required
error-admin-required
Error message
You need to have at least one admin
What it means
Thrown by POST roles.removeUserFromRole when role._id === 'admin', adminCount === 1, and the operation would remove the last admin. This is a safety guard preventing lockout. Returns a structured Meteor.Error('error-admin-required', 'You need to have at least one admin').
Source
Thrown at apps/meteor/server/api/v1/roles.ts:303
if (!user) {
throw new Meteor.Error('error-invalid-user', 'There is no user with this username');
}
const role = await Roles.findOneById(roleId);
if (!role) {
throw new Meteor.Error('error-invalid-roleId', 'This role does not exist');
}
if (!(await hasAnyRoleAsync(user._id, [role._id], scope))) {
throw new Meteor.Error('error-user-not-in-role', 'User is not in this role');
}
if (role._id === 'admin') {
const adminCount = await Roles.countUsersInRole('admin');
if (adminCount === 1) {
throw new Meteor.Error('error-admin-required', 'You need to have at least one admin');
}
}
await removeUserFromRolesAsync(user._id, [role._id], scope);
if (settings.get('UI_DisplayRoles')) {
void api.broadcast('user.roleUpdate', {
type: 'removed',
_id: role._id,
u: {
_id: user._id,
username: user.username,
},
scope,
});
}
return API.v1.success({View on GitHub (pinned to f9d3ec372b)
Solutions
- Promote at least one other user to admin first via roles.addUserToRole, then retry the removal.
- If the intent is to change the admin account, grant admin to the new user before revoking the old one.
- In automation, check adminCount via roles.getUsersInRole?role=admin and guard against count <= 1.
Example fix
// before
await fetch('/api/v1/roles.removeUserFromRole', { method:'POST', body: JSON.stringify({ roleId: 'admin', username }) });
// after - ensure a second admin exists first
const { total } = await fetch('/api/v1/roles.getUsersInRole?role=admin').then(r=>r.json());
if (total <= 1) {
await fetch('/api/v1/roles.addUserToRole', { method:'POST', body: JSON.stringify({ roleId:'admin', username: successor }) });
}
await fetch('/api/v1/roles.removeUserFromRole', { method:'POST', body: JSON.stringify({ roleId:'admin', username }) }); Defensive patterns
Strategy: validation
Validate before calling
// Never remove the last admin: ensure >= 2 admins first
const { total } = await fetch('/api/v1/roles.getUsersInRole?role=admin').then(r => r.json());
if (total <= 1) {
await fetch('/api/v1/roles.addUserToRole', { method:'POST', body: JSON.stringify({ roleId:'admin', username: successor }) });
}
await fetch('/api/v1/roles.removeUserFromRole', { method:'POST', body: JSON.stringify({ roleId:'admin', username }) }); Try / catch
try {
await fetch('/api/v1/roles.removeUserFromRole', {method:'POST',body:JSON.stringify({roleId:'admin',username})}).then(r=>r.json());
} catch (e) {
if (e.error === 'error-admin-required') { /* promote another admin, then retry */ }
} Prevention
- Promote a successor admin before demoting the current one.
- In automation, assert adminCount > 1 before any admin removal.
When it happens
Trigger: POST /api/v1/roles.removeUserFromRole with roleId 'admin' (or the admin role _id) for the only remaining administrator, globally.
Common situations: Demoting/removing the sole admin account; cleanup script strips all admin grants; removing a user who is the last admin before promoting another.
Related errors
- error-role-protected
- error-role-in-use
- error-action-not-allowed
- error-duplicate-role-names-not-allowed
- error-invalid-param
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/02c3e36ec2a4b11b.
Report an issue: GitHub.