RocketChat/Rocket.Chat · error · Meteor.Error

error-action-not-allowed

error-action-not-allowed

Error message

Not allowed

What it means

The catch-all authorization failure in deleteMessageValidatingPermission (deleteMessage.ts:20-27): thrown when the original message cannot be found, the user cannot be found, or canDeleteMessageAsync returns false. That helper (authorization/canDeleteMessage.ts) denies when the room is gone/inaccessible, the user lacks force-delete-message, Message_AllowDeleting is off, the user has neither delete-message nor delete-own-message permission for the room, or the Message_AllowDeleting_BlockDeleteInMinutes window has elapsed.

Source

Thrown at apps/meteor/server/lib/messages/deleteMessage.ts:25

import { settings } from '../../settings';
import { canDeleteMessageAsync } from '../authorization/canDeleteMessage';
import { callbacks } from '../callbacks';
import { FileUpload } from '../media/file-upload';
import { notifyOnRoomChangedById, notifyOnMessageChange, notifyOnSubscriptionChangedByRoomIdAndUserIds } from '../notifyListener';

export const deleteMessageValidatingPermission = async (message: AtLeast<IMessage, '_id'>, userId: IUser['_id']): Promise<void> => {
	if (!message?._id) {
		throw new Meteor.Error('error-invalid-message', 'Invalid message');
	}
	if (!userId) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user');
	}

	const user = await Users.findOneById(userId);
	const originalMessage = await Messages.findOneById(message._id);

	if (!originalMessage || !user || !(await canDeleteMessageAsync(user, originalMessage))) {
		throw new Meteor.Error('error-action-not-allowed', 'Not allowed');
	}

	return deleteMessage(originalMessage, user);
};

export async function deleteMessage(message: IMessage, user: IUser): Promise<void> {
	const deletedMsg: IMessage | null = await Messages.findOneById(message._id);
	const isThread = (deletedMsg?.tcount || 0) > 0;
	const keepHistory = settings.get('Message_KeepHistory') || isThread;
	const showDeletedStatus = settings.get('Message_ShowDeletedStatus') || isThread;

	const room = await Rooms.findOneById(message.rid, { projection: { lastMessage: 1, prid: 1, mid: 1, federated: 1, federation: 1 } });

	if (deletedMsg) {
		const prevent = await Apps.self?.triggerEvent(AppEvents.IPreMessageDeletePrevent, deletedMsg);
		if (prevent) {
			throw new Meteor.Error('error-app-prevented-deleting', 'A Rocket.Chat App prevented the message deleting.');
		}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Verify the message still exists (Messages.findOneById) before deleting - it may already be gone
  2. Check the acting user's room permissions: delete-own-message for own messages, delete-message for others', force-delete-message/bypass-time-limit-edit-and-delete to override limits
  3. Review Message_AllowDeleting and Message_AllowDeleting_BlockDeleteInMinutes settings if legit deletes fail
  4. Handle the race: treat 'already deleted' as success in idempotent clients
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await deleteMessageValidatingPermission({ _id }, userId);
} catch (error: any) {
  if (error instanceof Meteor.Error && error.error === 'error-action-not-allowed') {
    // check: message still exists? user has delete-message/delete-own-message?
    // Message_AllowDeleting on? delete window elapsed?
    showCannotDeleteMessage(_id);
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Deleting someone else's message without the room-scoped delete-message permission; Message_AllowDeleting disabled server-wide; the delete window (Message_AllowDeleting_BlockDeleteInMinutes) expired; the message id no longer exists (already deleted or wrong id); the user lost access to the room.

Common situations: Regular users trying to delete moderators' messages; tight compliance configs with a 1-minute delete window; deleting in rooms the user left or was removed from; double-delete races where the first delete already removed the message.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/6fcf2b7d6e76d66b. Report an issue: GitHub.