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
- Pass a valid message anchor: Meteor.call('unreadMessages', { _id: messageId })
- To mark a whole room unread from its last message, pass the room id as the second argument instead
- 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
- Type the call site against the ServerMethods declaration to catch shape errors at compile time
- Always supply either a message { _id } or a room string - never neither
- Centralize method invocation in typed wrappers so payloads cannot be built ad hoc
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
- error-no-message-for-unread
- error-subscription-not-found
- error-invalid-user
- You can't send messages because the room is readonly.
- error-invalid-user
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/1a1d0773348fdae8.
Report an issue: GitHub.