RocketChat/Rocket.Chat · error · Error

error-message-not-found

Error message

error-message-not-found

What it means

Thrown by GET push.get when Messages.findOneById(id) returns no document. The lookup uses the id query param (validated by isPushGetProps). Note this is a plain new Error('error-message-not-found'), not a Meteor.Error, so it surfaces as a generic 500-style failure rather than a structured error body. It guards the push-notification retrieval path before room access is even checked.

Source

Thrown at apps/meteor/server/api/v1/push.ts:311

			authRequired: true,
			query: isPushGetProps,
			response: {
				200: pushGetResponseSchema,
				400: validateBadRequestErrorResponse,
				401: validateUnauthorizedErrorResponse,
			},
		},
		async function action() {
			const { id } = this.queryParams;

			const receiver = await Users.findOneById(this.userId);
			if (!receiver) {
				throw new Error('error-user-not-found');
			}

			const message = await Messages.findOneById(id);
			if (!message) {
				throw new Error('error-message-not-found');
			}

			const room = await Rooms.findOneById(message.rid);
			if (!room) {
				throw new Error('error-room-not-found');
			}

			if (!(await canAccessRoomAsync(room, receiver))) {
				throw new Error('error-not-allowed');
			}

			const data = await PushNotification.getNotificationForMessageId({ receiver, room, message });

			return API.v1.success({ data });
		},
	)
	.get(
		'push.info',

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Confirm the message _id via GET /api/v1/chat.getMessage?msgId=<id> before calling push.get.
  2. Verify the id was copied from the notification payload's message id field, not the room or thread id.
  3. Handle the error gracefully on the client (the message may legitimately be gone) rather than retrying the same id.
  4. If the error body is unstructured (plain Error), check server logs for the exact throw site to distinguish it from error-room-not-found.

Example fix

// before
await fetch(`/api/v1/push.get?id=${id}`);

// after
const exists = await fetch(`/api/v1/chat.getMessage?msgId=${id}`).then(r => r.json());
if (!exists.message) {
  // message no longer available; skip push info fetch
  return null;
}
await fetch(`/api/v1/push.get?id=${id}`);
Defensive patterns

Strategy: validation

Validate before calling

// Validate message id format and existence before push.get
async function safePushGet(id: string, authHeaders: HeadersInit) {
  if (!id || typeof id !== 'string') throw new Error('id required');
  const msg = await fetch(`/api/v1/chat.getMessage?msgId=${encodeURIComponent(id)}`, { headers: authHeaders }).then(r => r.json());
  if (!msg.success || !msg.message) return null; // message gone, skip
  return fetch(`/api/v1/push.get?id=${encodeURIComponent(id)}`, { headers: authHeaders }).then(r => r.json());
}

Type guard

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

Try / catch

try {
  await fetch(`/api/v1/push.get?id=${id}`).then(r => r.json());
} catch (e) {
  // plain Error (not Meteor.Error) -> generic failure; log id and move on
  if (String(e).includes('error-message-not-found')) { /* message gone */ }
}

Prevention

When it happens

Trigger: GET /api/v1/push.get?id=<id> where id does not match any message document (typo, deleted message, id from another workspace, or id omitted/null despite the query schema).

Common situations: Client caches a stale message id; the message was hard-deleted between notification dispatch and the info fetch; integration passes a thread/discussion parent id instead of the actual message _id.

Related errors


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