RocketChat/Rocket.Chat · error · Error

Message not found

Error message

Message not found

What it means

Thrown by getMessageByID in the chats data layer when neither the local reactive store (Messages.state) nor the server fallback (GET /v1/chat.getMessage) returned a message for the given mid. findMessageByID first checks local state (excluding hidden messages) then queries the server; if both yield nothing, the message truly does not exist or is inaccessible.

Source

Thrown at apps/meteor/client/lib/chats/data.ts:45

			_id: originalMessage?._id ?? Random.id(),
			rid: effectiveRID,
			...(effectiveTMID && {
				tmid: effectiveTMID,
				...(sendToChannel && { tshow: sendToChannel }),
			}),
			msg,
		} as IMessage;
	};

	const findMessageByID = async (mid: IMessage['_id']): Promise<IMessage | null> =>
		Messages.state.find((record) => record._id === mid && record._hidden !== true) ??
		sdk.rest.get('/v1/chat.getMessage', { msgId: mid }).then((response) => mapMessageFromApi(response.message));

	const getMessageByID = async (mid: IMessage['_id']): Promise<IMessage> => {
		const message = await findMessageByID(mid);

		if (!message) {
			throw new Error('Message not found');
		}

		return message;
	};

	const findLastMessage = async (): Promise<IMessage | undefined> =>
		Messages.state.findFirst(
			(record) => record.rid === rid && (tmid ? record.tmid === tmid : !record.tmid) && record._hidden !== true,
			(a, b) => b.ts.getTime() - a.ts.getTime(),
		);

	const getLastMessage = async (): Promise<IMessage> => {
		const message = await findLastMessage();

		if (!message) {
			throw new Error('Message not found');
		}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Verify the mid is correct and not truncated (deep links/notifications can mangle ids).
  2. Confirm the user has read access to the room the message belongs to.
  3. Handle the thrown error to show a 'message no longer available' state instead of crashing.
  4. If the message was deleted, refresh the thread/room list to reflect the new state.
  5. For hidden messages, ensure the caller expects a hidden message to be treated as absent.
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify read access before lookup
if (!hasAtLeastOnePermission('read-message', roomId)) {
  throw new Error('No read access');
}

Type guard

function isFoundMessage(m: IMessage | null | undefined): m is IMessage {
  return m != null;
}

Try / catch

try {
  const msg = await getMessageByID(mid);
} catch (e) {
  if ((e as Error).message === 'Message not found') {
    showMessageUnavailable();
  }
}

Prevention

When it happens

Trigger: Calling getMessageByID(mid) where mid does not exist, was deleted, belongs to a room the user cannot read, or the server returned no message in the chat.getMessage response (response.message falsy). The local lookup also filters out _hidden === true records, so a hidden message in local state still falls through to the server.

Common situations: Stale message id from an old notification/deep link; the message was deleted between fetch and access; the user lacks 'read-message'/'preview-room' permission for the room; the room is a private channel the user was removed from; a deep link with a truncated/typo'd id.

Related errors


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