RocketChat/Rocket.Chat · error · Meteor.Error
error-action-not-allowed
error-action-not-allowed
Error message
Leaving the app without an active admin is not allowed
What it means
setUserActiveStatus throws error-action-not-allowed when deactivating (active=false) the last remaining active admin: it checks the target is an admin (findOneAdmin) and that the count of active users in the admin role is exactly 1. This is a deliberate guard to prevent locking the workspace out of administration.
Source
Thrown at apps/meteor/server/lib/users/setUserActiveStatus.ts:78
const user = await Users.findOneById(userId);
if (!user) {
return false;
}
if (isUserFederated(user)) {
throw new Meteor.Error('error-user-is-federated', 'Cannot change federated users status', {
method: 'setUserActiveStatus',
});
}
// Users without username can't do anything, so there is no need to check for owned rooms
if (user.username != null && !active) {
const userAdmin = await Users.findOneAdmin(userId || '');
const adminsCount = await Users.countActiveUsersInRoles(['admin']);
if (userAdmin && adminsCount === 1) {
throw new Meteor.Error('error-action-not-allowed', 'Leaving the app without an active admin is not allowed', {
method: 'removeUserFromRole',
action: 'Remove_last_admin',
});
}
const subscribedRooms = await getSubscribedRoomsForUserWithDetails(userId);
// give omnichannel rooms a special treatment :)
const chatSubscribedRooms = subscribedRooms.filter(({ t }) => t !== 'l');
const livechatSubscribedRooms = subscribedRooms.filter(({ t }) => t === 'l');
if (shouldRemoveOrChangeOwner(chatSubscribedRooms) && !confirmRelinquish) {
const rooms = await getUserSingleOwnedRooms(chatSubscribedRooms as []);
throw new Meteor.Error('user-last-owner', '', rooms);
}
// We don't want one killing the other :)
await Promise.allSettled([
closeOmnichannelConversations(user, livechatSubscribedRooms, executedBy),View on GitHub (pinned to b2c16d5842)
Solutions
- Promote another (active) user to the admin role first, then retry the deactivation.
- Or reactivate an existing inactive admin before disabling the current one.
- Adjust bulk scripts to skip admins or verify at least one other active admin remains before each deactivation.
Defensive patterns
Strategy: validation
Validate before calling
const user = await Users.findOneAdmin(userId);
if (user) {
const activeAdmins = await Users.countActiveUsersInRoles(['admin']);
if (activeAdmins <= 1) {
throw new Meteor.Error('error-last-admin', 'Promote another active admin before deactivating this user');
}
}
await setUserActiveStatus(userId, false, confirmRelinquish); Prevention
- Before offboarding any admin, verify at least one other active admin exists.
- Bulk deactivation scripts must skip users in the admin role unless a successor is confirmed.
- Keep a break-glass admin account active on production workspaces.
When it happens
Trigger: Deactivating the sole active admin account — typically via the admin UI's deactivate action or the REST users.deactivate endpoint; also hit by scripts that deactivate users in bulk including every admin.
Common situations: Offboarding the founding admin without naming a successor; test/demo workspaces with a single admin account; automated deactivation scripts not excluding admins.
Related errors
- error-not-authorized
- error-action-not-allowed
- error-invalid-permission
- error-user-is-federated
- error-not-authorized
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/baffed96af7adcd1.
Report an issue: GitHub.