RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room

error-invalid-room

Error message

error-invalid-room

What it means

blockUserMethod throws error-invalid-room with method 'blockUser' when Rooms.findOne({ _id: rid }) returns null: no room exists with that id. This is the first of three identical-code guards in the method (not found, wrong type, missing subscription).

Source

Thrown at apps/meteor/server/lib/users/blockUser.ts:12

import { Subscriptions, Rooms } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { RoomMemberActions } from '../../../definition/IRoomTypeConfig';
import { notifyOnSubscriptionChangedByRoomIdAndUserIds } from '../notifyListener';
import { roomCoordinator } from '../rooms/roomCoordinator';

export const blockUserMethod = async (userId: string, { rid, blocked }: { rid: string; blocked: string }): Promise<void> => {
	const room = await Rooms.findOne({ _id: rid });

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

	if (!(await roomCoordinator.getRoomDirectives(room.t).allowMemberAction(room, RoomMemberActions.BLOCK, userId))) {
		throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'blockUser' });
	}

	const [blockedUser, blockerUser] = await Promise.all([
		Subscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),
		Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),
	]);

	if (!blockedUser || !blockerUser) {
		throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'blockUser' });
	}

	const [blockedResponse, blockerResponse] = await Subscriptions.setBlockedByRoomId(rid, blocked, userId);

	const listenerUsers = [...(blockedResponse?.modifiedCount ? [blocked] : []), ...(blockerResponse?.modifiedCount ? [userId] : [])];

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Refresh the room list and confirm the room still exists (GET /api/v1/rooms.info?roomId=...)
  2. If the room was deleted, drop the local state pointing at it; there is nothing to block in
  3. Verify the rid comes from the same server/deployment as the call

Example fix

// before
Meteor.call('blockUser', { rid, blocked });

// after
const room = await call('GET', 'rooms.info', { roomId: rid }); // throws clean 404 if deleted
if (!room) throw new Error('Room no longer exists');
Meteor.call('blockUser', { rid, blocked });
Defensive patterns

Strategy: validation

Validate before calling

const room = await Rooms.findOneById(rid, { projections: { _id: 1 } });
if (!room) throw new Error('Room does not exist (maybe deleted)');
Meteor.call('blockUser', { rid, blocked });

Type guard

const isInvalidRoomError = (e: unknown): boolean =>
  typeof e === 'object' && e !== null && 'error' in e && (e as { error?: string }).error === 'error-invalid-room';

Try / catch

try {
  Meteor.call('blockUser', { rid, blocked });
} catch (e) {
  if (isInvalidRoomError(e) && /Invalid room/.test((e as { reason?: string }).reason ?? '')) {
    invalidateCachedRoom(rid); // room is gone, refresh state
  }
}

Prevention

When it happens

Trigger: Meteor.call('blockUser', [{ rid, blocked }]) or the im.blockUser REST route with a stale rid: the room was deleted while the client still held the id, a typo in the id, or a rid copied from another workspace/environment.

Common situations: Client cached a DM room id across a room deletion or re-installation; test fixtures using fabricated ObjectIds; environment mismatch (dev id used against prod).

Related errors


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