RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-message

error-invalid-message

Error message

Invalid message

What it means

deleteMessageValidatingPermission (apps/meteor/server/lib/messages/deleteMessage.ts:13-16) is the entry point behind the deleteMessage DDP method and the chat.delete REST call. It requires a truthy message._id before doing anything else; a message object without one throws error-invalid-message 'Invalid message'. This is an input-shape check that runs before any permission lookup.

Source

Thrown at apps/meteor/server/lib/messages/deleteMessage.ts:15

import { AppEvents, Apps } from '@rocket.chat/apps';
import { api, Message } from '@rocket.chat/core-services';
import { isThreadMessage, type AtLeast, type IMessage, type IRoom, type IThreadMessage, type IUser } from '@rocket.chat/core-typings';
import { Messages, Rooms, Uploads, Users, ReadReceipts, ReadReceiptsArchive, Subscriptions } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { settings } from '../../settings';
import { canDeleteMessageAsync } from '../authorization/canDeleteMessage';
import { callbacks } from '../callbacks';
import { FileUpload } from '../media/file-upload';
import { notifyOnRoomChangedById, notifyOnMessageChange, notifyOnSubscriptionChangedByRoomIdAndUserIds } from '../notifyListener';

export const deleteMessageValidatingPermission = async (message: AtLeast<IMessage, '_id'>, userId: IUser['_id']): Promise<void> => {
	if (!message?._id) {
		throw new Meteor.Error('error-invalid-message', 'Invalid message');
	}
	if (!userId) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user');
	}

	const user = await Users.findOneById(userId);
	const originalMessage = await Messages.findOneById(message._id);

	if (!originalMessage || !user || !(await canDeleteMessageAsync(user, originalMessage))) {
		throw new Meteor.Error('error-action-not-allowed', 'Not allowed');
	}

	return deleteMessage(originalMessage, user);
};

export async function deleteMessage(message: IMessage, user: IUser): Promise<void> {
	const deletedMsg: IMessage | null = await Messages.findOneById(message._id);
	const isThread = (deletedMsg?.tcount || 0) > 0;

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pass the _id of an existing message: Meteor.call('deleteMessage', { _id }) or POST chat.delete with { roomId, msgId }
  2. Validate the payload shape before invoking the API (assert _id is a non-empty string)
  3. Log the offending payload when this fires - it almost always indicates a caller bug, not a server problem

Example fix

// before
Meteor.call('deleteMessage', { msg: message.msg }); // -> error-invalid-message
// after
Meteor.call('deleteMessage', { _id: message._id });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof message?._id !== 'string' || message._id.length === 0) {
  throw new TypeError('deleteMessage requires message._id');
}
await deleteMessageValidatingPermission(message, userId);

Type guard

const hasMessageId = (m: unknown): m is { _id: string } =>
  typeof m === 'object' && m !== null && typeof (m as any)._id === 'string' && (m as any)._id.length > 0;

Try / catch

try {
  await deleteMessageValidatingPermission(message, userId);
} catch (error: any) {
  if (error instanceof Meteor.Error && error.error === 'error-invalid-message') {
    // caller bug: payload lacks _id; fix the caller, do not retry
    logPayloadShapeError(message);
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling Meteor.call('deleteMessage', {}) or chat.delete with a body missing the messageId/_id field; passing a message stub built from a template/event payload that never had an id set; destructuring bugs that send { msg } instead of { _id }.

Common situations: Custom UI code calling the deletion method with the wrong object shape; integrations reacting to webhooks and deleting with an undefined id; race where the caller deletes based on a message that was never sent so no id exists.

Related errors


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