RocketChat/Rocket.Chat · error · Meteor.Error

error-action-not-allowed

error-action-not-allowed

Error message

Not allowed

What it means

In the message branch of unreadMessages (no room argument given), the code requires firstUnreadMessage._id to be a string; otherwise it throws Meteor.Error('error-action-not-allowed', 'Not allowed'). It is an argument-shape guard: the payload must be an object like { _id: '<messageId>' } for the message-anchored unread flow.

Source

Thrown at apps/meteor/server/lib/messaging/unread/unreadMessages.ts:42

		)[0];

		if (!lastMessage) {
			throw new Meteor.Error('error-no-message-for-unread', 'There are no messages to mark unread', {
				method: 'unreadMessages',
				action: 'Unread_messages',
			});
		}

		const setAsUnreadResponse = await Subscriptions.setAsUnreadByRoomIdAndUserId(lastMessage.rid, userId, lastMessage.ts);
		if (setAsUnreadResponse.modifiedCount) {
			void notifyOnSubscriptionChangedByRoomIdAndUserId(lastMessage.rid, userId);
		}

		return;
	}

	if (typeof firstUnreadMessage?._id !== 'string') {
		throw new Meteor.Error('error-action-not-allowed', 'Not allowed', {
			method: 'unreadMessages',
			action: 'Unread_messages',
		});
	}

	const originalMessage = await Messages.findOneById(firstUnreadMessage._id, {
		projection: {
			u: 1,
			rid: 1,
			ts: 1,
		},
	});
	if (!originalMessage || userId === originalMessage.u._id) {
		throw new Meteor.Error('error-action-not-allowed', 'Not allowed', {
			method: 'unreadMessages',
			action: 'Unread_messages',
		});
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pass a valid message anchor: Meteor.call('unreadMessages', { _id: messageId })
  2. To mark a whole room unread from its last message, pass the room id as the second argument instead
  3. Type the call site against the ServerMethods declaration so shape errors surface at compile time

Example fix

// before
Meteor.call('unreadMessages'); // no message and no room

// after
Meteor.call('unreadMessages', { _id: firstUnreadMessageId }, rid);
Defensive patterns

Strategy: type-guard

Validate before calling

const hasMessageAnchor = typeof firstUnreadMessage?._id === 'string';
const hasRoom = typeof room === 'string';
if (hasMessageAnchor || hasRoom) {
  Meteor.call('unreadMessages', firstUnreadMessage, room);
}

Type guard

const isFirstUnreadPayload = (v: unknown): v is { _id: string } =>
  typeof v === 'object' && v !== null && typeof (v as { _id?: unknown })._id === 'string';

Try / catch

Meteor.call('unreadMessages', first, rid, (err) => {
  if (err?.error === 'error-action-not-allowed' && !first?._id && !rid) {
    fixPayloadAndRetry(); // neither message anchor nor room was supplied
  }
});

Prevention

When it happens

Trigger: Meteor.call('unreadMessages') with firstUnreadMessage undefined/null, an object without _id, or a non-string _id (number/ObjectId), while also omitting the second room argument.

Common situations: Clients calling the method with no arguments expecting 'unread everything'; malformed payloads from integrations; refactors that changed the argument shape without updating callers.

Related errors


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