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
- Pass the _id of an existing message: Meteor.call('deleteMessage', { _id }) or POST chat.delete with { roomId, msgId }
- Validate the payload shape before invoking the API (assert _id is a non-empty string)
- 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
- Always pass {_id} from the message document you render
- Type your call sites against AtLeast<IMessage, '_id'>
- Assert payload shape at integration boundaries
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
- error-invalid-user
- error-action-not-allowed
- error-app-prevented-deleting
- error-invalid-room
- invalid-params
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/eacba7e16ed47e6d.
Report an issue: GitHub.