RocketChat/Rocket.Chat · error · Error
Invalid message id
Error message
Invalid message id
What it means
Thrown by AppModerationBridge.report when the messageId argument is falsy. The bridge is the Apps Engine entry point for message reporting; it forwards to server/lib/moderation/reportMessage, which itself re-validates and will throw 'error-invalid-message_id' if the id does not correspond to an existing message. This particular throw is the cheap pre-check that prevents a needless DB round-trip.
Source
Thrown at apps/meteor/app/apps/server/bridges/moderation.ts:18
import type { IAppServerOrchestrator } from '@rocket.chat/apps';
import { ModerationBridge } from '@rocket.chat/apps/dist/server/bridges/ModerationBridge';
import type { IMessage } from '@rocket.chat/apps-engine/definition/messages';
import type { IUser } from '@rocket.chat/apps-engine/definition/users';
import { ModerationReports } from '@rocket.chat/models';
import { reportMessage } from '../../../../server/lib/moderation/reportMessage';
export class AppModerationBridge extends ModerationBridge {
constructor(private readonly orch: IAppServerOrchestrator) {
super();
}
protected async report(messageId: IMessage['id'], description: string, userId: string, appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is creating a new report.`);
if (!messageId) {
throw new Error('Invalid message id');
}
if (!description) {
throw new Error('Invalid description');
}
await reportMessage(messageId, description, userId || 'rocket.cat');
}
protected async dismissReportsByMessageId(messageId: IMessage['id'], reason: string, action: string, appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is dismissing reports by message id.`);
if (!messageId) {
throw new Error('Invalid message id');
}
await ModerationReports.hideMessageReportsByMessageId(messageId, appId, reason, action);
}View on GitHub (pinned to f9d3ec372b)
Solutions
- Ensure messageId is the persisted message's id — await the send and use the returned id before reporting.
- Guard the call: `if (!messageId) return;` or surface a user-facing error instead of letting the bridge throw.
- When handling events, read message.id defensively and skip when absent.
Example fix
// before
await moderation.report('', 'spam', userId, appId);
// after
if (message.id) {
await moderation.report(message.id, 'spam', userId, appId);
} Defensive patterns
Strategy: validation
Validate before calling
if (!messageId || typeof messageId !== 'string') {
throw new Error('A valid message id is required to report');
}
await moderation.report(messageId, description, userId, appId); Type guard
function isMessageId(value: unknown): value is string {
return typeof value === 'string' && value.length > 0;
} Prevention
- Always await the send that produces the message id before wiring a report action to it.
- Read message.id defensively from event payloads and skip the action when absent.
- Validate required ids at the App's action-handler boundary, not deep in the call chain.
When it happens
Trigger: An App calls the moderation accessor's report endpoint with messageId set to undefined, null, '' or 0 — typically because the App held a message object whose id field was never populated (e.g. a message constructed locally but not yet persisted) or a value extracted from an event payload that was missing the id property.
Common situations: Calling report on a message stub built for sending before the send completed; deserializing a cached message that lost its id; chaining report after a send whose return value (the id) was not awaited; UI actions that pass an empty selection.
Related errors
- Invalid description
- Invalid user id
- Invalid Api parameter provided, it must be a valid IApi obje
- Invalid command parameter provided, must be a string.
- Invalid Slash Command parameter provided, it must be a valid
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/e9a767ec52f55f2f.
Report an issue: GitHub.