RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room

error-invalid-room

Error message

Invalid room

What it means

loadMissedMessages throws error-invalid-room when rid is falsy. Because check(rid, String) runs first and enforces the type, the only value that reaches this throw is the empty string '' (null/undefined/number fail earlier with a Match failed error instead). Two quirks: the error's method metadata says 'getUsersOfRoom' — a copy-paste artifact — and the method is deprecated since 9.0.0 in favor of /v1/chat.syncMessages. Note that failing canAccessRoomIdAsync does NOT throw here; it returns false.

Source

Thrown at apps/meteor/server/meteor-methods/messages/loadMissedMessages.ts:26

import { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		loadMissedMessages(rid: IRoom['_id'], ts: Date): Promise<false | IMessage[]>;
	}
}

Meteor.methods<ServerMethods>({
	async loadMissedMessages(rid, start) {
		methodDeprecationLogger.method('loadMissedMessages', '9.0.0', '/v1/chat.syncMessages');
		check(rid, String);
		check(start, Date);

		const fromId = Meteor.userId() ?? undefined;

		if (!rid) {
			throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getUsersOfRoom' });
		}

		if (!(await canAccessRoomIdAsync(rid, fromId))) {
			return false;
		}

		return Messages.findVisibleByRoomIdAfterTimestamp(rid, start, true, {
			sort: {
				ts: -1,
			},
		}).toArray();
	},
});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Guard rid before calling — only call when it is a non-empty string
  2. Fix the source of the empty rid (await the room record, validate route params)
  3. Migrate to /v1/chat.syncMessages, which validates its own input

Example fix

// before
const messages = await Meteor.callAsync('loadMissedMessages', rid, lastSync);

// after
if (typeof rid !== 'string' || rid.length === 0) {
  // wait for the room id instead of calling with ''
  return;
}
const messages = await Meteor.callAsync('loadMissedMessages', rid, lastSync);
Defensive patterns

Strategy: validation

Validate before calling

if (typeof rid !== 'string' || rid.length === 0) {
  // wait for the room record — never call loadMissedMessages with ''
}

Type guard

const isNonEmptyRoomId = (rid: unknown): rid is string =>
  typeof rid === 'string' && rid.trim().length > 0;

Prevention

When it happens

Trigger: Meteor.call('loadMissedMessages', '', startDate) — the rid comes from an unset variable, an empty route param, or a room record that has not loaded yet when the sync fires.

Common situations: Races where loadMissedMessages fires before the room subscription delivers the rid; refactors that renamed variables and accidentally pass ''; optional :rid route params rendered without validation.

Related errors


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