RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room

error-invalid-room

Error message

Invalid room

What it means

loadNextMessages throws error-invalid-room when rid is falsy. check(rid, String) already guaranteed the type, so this branch is reachable only with the empty string '' — any null/undefined/non-string would have failed check() with a Match error before reaching this line.

Source

Thrown at apps/meteor/server/meteor-methods/messages/loadNextMessages.ts:29

	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		loadNextMessages(rid: IRoom['_id'], end?: Date, limit?: number): Promise<{ messages: IMessage[] }>;
	}
}

Meteor.methods<ServerMethods>({
	async loadNextMessages(rid, end, limit = 20) {
		check(rid, String);
		check(limit, Number);

		if (!Meteor.userId()) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', {
				method: 'loadNextMessages',
			});
		}

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

		const fromId = Meteor.userId();

		if (!fromId || !(await canAccessRoomIdAsync(rid, fromId))) {
			throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'loadNextMessages' });
		}

		let records;
		if (end) {
			records = await Messages.findVisibleByRoomIdAfterTimestamp(rid, end, true, {
				sort: {
					ts: 1,
				},
				limit,
			}).toArray();
		} else {
			records = await Messages.findVisibleByRoomId(rid, {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Guard rid (non-empty string) before calling
  2. Initialize rid from the room record/subscription and render loading state until it exists
  3. Fail fast in development when rid is missing to catch state bugs

Example fix

// before
const { messages } = await Meteor.callAsync('loadNextMessages', rid, end, limit);

// after
if (typeof rid !== 'string' || rid.length === 0) {
  return { messages: [] }; // or await room load
}
const { messages } = await Meteor.callAsync('loadNextMessages', rid, end, limit);
Defensive patterns

Strategy: validation

Validate before calling

if (typeof rid !== 'string' || rid.length === 0) {
  return { messages: [] }; // room id not ready yet
}

Type guard

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

Prevention

When it happens

Trigger: Meteor.call('loadNextMessages', '', end, limit) — rid read from an unset state field, an empty URL parameter, or a room subscription that has not delivered the record yet.

Common situations: Component renders before the room data arrives and passes an empty id; refactors that leave an intermediate variable uninitialized; optional route params used without a default.

Related errors


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