RocketChat/Rocket.Chat · warning · Meteor.Error

error-no-message-for-unread

error-no-message-for-unread

Error message

There are no messages to mark unread

What it means

When unreadMessages is called with a room id, it fetches the newest visible message via findVisibleByRoomId (limit 1, ts desc); if none exists it throws Meteor.Error('error-no-message-for-unread', 'There are no messages to mark unread'). The room has zero messages eligible for an unread marker - empty room, or every message invisible (deleted/hidden).

Source

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

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		unreadMessages(firstUnreadMessage?: Pick<IMessage, '_id'>, room?: IRoom['_id']): void;
	}
}

export const unreadMessages = async (userId: string, firstUnreadMessage?: Pick<IMessage, '_id'>, room?: IRoom['_id']): Promise<void> => {
	if (room && typeof room === 'string') {
		const lastMessage = (
			await Messages.findVisibleByRoomId(room, {
				limit: 1,
				sort: { ts: -1 },
			}).toArray()
		)[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',
		});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Client: gate the mark-unread action on room.lastMessage being present
  2. If messages were purged, acknowledge the room (mark read) instead of marking unread
  3. Skip the call when the local room cache shows no visible history

Example fix

// before
Meteor.call('unreadMessages', null, rid); // throws on empty rooms

// after
const room = Rooms.findOne({ _id: rid });
if (room?.lastMessage) {
  Meteor.call('unreadMessages', null, rid);
Defensive patterns

Strategy: validation

Validate before calling

// The rooms stream carries lastMessage - use it as the precondition
const room = Rooms.findOne({ _id: rid });
if (room?.lastMessage) {
  Meteor.call('unreadMessages', null, rid);
} else {
  markRoomAsRead(rid); // nothing to unread
}

Try / catch

Meteor.call('unreadMessages', null, rid, (err) => {
  if (err?.error === 'error-no-message-for-unread') {
    markRoomAsRead(rid); // benign - clear any unread badge and move on
  }
});

Prevention

When it happens

Trigger: Meteor.call('unreadMessages', undefined, roomId) on a room with no visible messages: a freshly created empty channel, a room whose only messages were deleted, or a retention purge that removed everything.

Common situations: Mark-as-unread offered on empty rooms; messages purged while the room was already read; UI not disabling the unread action when lastMessage is absent.

Related errors


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