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
- Refresh the room list and confirm the room still exists (GET /api/v1/rooms.info?roomId=...)
- If the room was deleted, drop the local state pointing at it; there is nothing to block in
- 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
- Invalidate cached room ids when rooms.info returns 404
- Treat room deletion events (streamer) as a signal to drop stored rids
- Never reuse ids across deployments
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
- room_is_blocked
- invalid-channel
- error-direct-message-max-user-exceeded
- The required "roomId" or "roomName" param provided does not
- error-invalid-room
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/cd70e0d04f3ae4ef.
Report an issue: GitHub.