RocketChat/Rocket.Chat · error · Meteor.Error
error-not-allowed
error-not-allowed
Error message
Not allowed
What it means
addRoomModerator authorizes via hasPermissionAsync(fromUserId, 'set-moderator', rid) OR the room being federated (isRoomFederated). error-not-allowed means the caller lacks set-moderator on that room and the room is not federated, so neither branch applies. For federated rooms the permission check is skipped and authority is delegated to the federation flow instead.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/addRoomModerator.ts:38
addRoomModerator(rid: IRoom['_id'], userId: IUser['_id']): boolean;
}
}
export const addRoomModerator = async (fromUserId: IUser['_id'], rid: IRoom['_id'], userId: IUser['_id']): Promise<boolean> => {
check(rid, String);
check(userId, String);
const room = await Rooms.findOneById(rid, { projection: { t: 1, federated: 1, federation: 1 } });
if (!room) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'addRoomModerator',
});
}
const isFederated = isRoomFederated(room);
if (!(await hasPermissionAsync(fromUserId, 'set-moderator', rid)) && !isFederated) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'addRoomModerator',
});
}
if (isFederated && !isFederationEnabled()) {
throw new FederationMatrixInvalidConfigurationError('unable to change room owners');
}
const user = await Users.findOneById(userId);
if (!user?.username) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'addRoomModerator',
});
}
const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);
View on GitHub (pinned to b2c16d5842)
Solutions
- Grant set-moderator to the caller's role, globally or scoped to that room.
- Use REST channels.addModerator/groups.addModerator with an authorized token.
- Catch error-not-allowed and hide the promote action for callers without the permission.
Defensive patterns
Strategy: try-catch
Validate before calling
// hide 'Set as moderator' unless the caller holds set-moderator for the room
if (!(await hasPermission('set-moderator', rid))) {
// do not offer the action
} Try / catch
try {
await Meteor.callAsync('addRoomModerator', rid, userId);
} catch (e: any) {
if (e?.error === 'error-not-allowed') {
// caller lacks set-moderator and room is not federated: surface auth error
}
} Prevention
- Check set-moderator (room scope) before exposing the promote action.
- Remember federated rooms bypass the permission check - expect different behavior there.
- Use elevated tokens for automated moderation changes.
When it happens
Trigger: A non-moderator calling addRoomModerator (or channels.addModerator/groups.addModerator) on an ordinary non-federated channel; room-scoped set-moderator overrides that exclude the caller.
Common situations: Members assuming moderator rights; permission grids trimmed by admins; custom tooling using low-privilege accounts for role changes.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- error-invalid-user
- error-not-allowed
- error-invalid-role
- The required "roomId" or "roomName" param provided does not
- error-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/375e3d2e80f96861.
Report an issue: GitHub.