RocketChat/Rocket.Chat · error · Meteor.Error
error-not-allowed
error-not-allowed
Error message
Not allowed
What it means
First guard in the cleanRoomHistory execution path: hasPermissionAsync(userId, 'clean-channel-history', roomId) returned false. Cleaning/pruning room history requires the clean-channel-history permission, evaluated against the target room - by default an admin/moderator-level grant.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/cleanRoomHistory.ts:45
}
export const cleanRoomHistoryMethod = async (
userId: string,
{
roomId,
latest,
oldest,
inclusive = true,
limit,
excludePinned = false,
ignoreDiscussion = true,
filesOnly = false,
fromUsers = [],
ignoreThreads,
}: CleanRoomHistoryParams,
): Promise<number> => {
if (!(await hasPermissionAsync(userId, 'clean-channel-history', roomId))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'cleanRoomHistory' });
}
const room = await findRoomByIdOrName({ params: { roomId } });
if (!room || !(await canAccessRoomAsync(room, { _id: userId }))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'cleanRoomHistory' });
}
return cleanRoomHistory({
rid: roomId,
latest,
oldest,
inclusive,
limit,
excludePinned,
ignoreDiscussion,
filesOnly,
fromUsers,View on GitHub (pinned to b2c16d5842)
Solutions
- Grant clean-channel-history to the acting user's role (Administration > Permissions).
- Run the prune as an admin or a role that holds the permission.
- Pre-check the permission client-side and hide the prune/clean action when absent.
Example fix
// before
Meteor.call('cleanRoomHistory', roomId, latest, oldest);
// after
if (hasPermission(Meteor.userId(), 'clean-channel-history', roomId)) {
Meteor.call('cleanRoomHistory', roomId, latest, oldest);
} else {
showToast('Cleaning history requires the clean-channel-history permission');
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!hasPermission(Meteor.userId(), 'clean-channel-history', roomId)) {
// do not offer or attempt history cleaning for this room
} Try / catch
try {
const removed = await Meteor.callAsync('cleanRoomHistory', roomId, latest, oldest);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-not-allowed') {
// caller lacks clean-channel-history - surface an admin-actionable message
showToast('Cleaning history requires the clean-channel-history permission');
return;
}
throw e;
} Prevention
- Expose prune/clean UI only to roles holding clean-channel-history.
- Scope the permission check to the exact room id being cleaned.
- For retention jobs, run as an admin/service account that holds the permission globally.
When it happens
Trigger: A user without clean-channel-history invokes the cleanRoomHistory method (or the prune-history UI); the permission exists globally but is not granted at the target room scope; role changes removed it after the UI was rendered.
Common situations: Moderators expected to prune but whose role lacks clean-channel-history; retention automations running under a normal user account; fresh workspaces where the permission was never assigned to custom roles.
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
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/02382e262460d9ee.
Report an issue: GitHub.