RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-message

error-invalid-message

Error message

Invalid message

What it means

Thrown by getReadReceiptsFunction when Messages.findOneById(messageId) returns null. The lookup projects _id, rid, and receiptsArchived; a missing record means the message id does not correspond to an existing message. Code is 'error-invalid-message'.

Source

Thrown at apps/meteor/ee/server/meteor-methods/getReadReceipts.ts:27

import { methodDeprecationLogger } from '../../../server/lib/deprecationWarningLogger';
import { ReadReceipt } from '../lib/message-read-receipt/ReadReceipt';

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		getReadReceipts(options: { messageId: IMessage['_id'] }): IReadReceiptWithUser[];
	}
}

export const getReadReceiptsFunction = async function (messageId: IMessage['_id'], userId: string): Promise<IReadReceiptWithUser[]> {
	if (!License.hasModule('message-read-receipt')) {
		throw new Meteor.Error('error-action-not-allowed', 'This is an enterprise feature', { method: 'getReadReceipts' });
	}
	check(messageId, String);

	const message = await Messages.findOneById(messageId, { projection: { _id: 1, rid: 1, receiptsArchived: 1 } });
	if (!message) {
		throw new Meteor.Error('error-invalid-message', 'Invalid message', {
			method: 'getReadReceipts',
		});
	}

	if (!(await canAccessRoomIdAsync(message.rid, userId))) {
		throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getReadReceipts' });
	}

	return ReadReceipt.getReceipts(message);
};

Meteor.methods<ServerMethods>({
	async getReadReceipts({ messageId }) {
		methodDeprecationLogger.method('getReadReceipts', '9.0.0', '/v1/chat.getMessageReadReceipts');

		check(messageId, String);

		const uid = Meteor.userId();

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Validate the messageId exists (Messages.findOneById) before calling the method.
  2. Handle the error in the client and close the read-receipt panel with a 'message not found' notice.
  3. Check retention/purge policies if valid messages disappear.

Example fix

// before
const receipts = await getReadReceiptsFunction(messageId, uid);

// after
const msg = await Messages.findOneById(messageId, { projection: { _id: 1 } });
if (!msg) throw new Error('Message not found');
const receipts = await getReadReceiptsFunction(messageId, uid);
Defensive patterns

Strategy: validation

Validate before calling

const msg = await Messages.findOneById(messageId, { projection: { _id: 1 } });
if (!msg) throw new Error('Message not found');
const receipts = await getReadReceiptsFunction(messageId, uid);

Type guard

function isMessageId(id: unknown): id is string {
  return typeof id === 'string' && id.length > 0;
}

Try / catch

try {
  await getReadReceiptsFunction(messageId, uid);
} catch (e) {
  if (isMeteorError(e, 'error-invalid-message')) {
    closeReadReceiptPanel('Message no longer exists.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling getReadReceipts with a messageId that does not exist, was deleted, or has not been inserted yet (eventual-consistency lag).

Common situations: Client holds a stale message id after deletion; message id mistyped or swapped; a message deleted by retention policy while its read-receipt panel was open.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/c722388c80f5a9f7. Report an issue: GitHub.