RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room

error-invalid-room

Error message

Invalid room

What it means

eraseRoom resolves the room (looking it up by id when a string is passed) and throws this Meteor.Error when no room document exists. Deletion of an already-absent room is refused rather than treated as a no-op.

Source

Thrown at apps/meteor/server/lib/eraseRoom.ts:15

import { AppEvents, Apps } from '@rocket.chat/apps';
import { Message, Team } from '@rocket.chat/core-services';
import type { IRoom, IUser, AtLeast } from '@rocket.chat/core-typings';
import { Rooms } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from './authorization/hasPermission';
import { deleteRoom } from './rooms/deleteRoom';
import { roomCoordinator } from './rooms/roomCoordinator';

export async function eraseRoom(roomOrId: string | IRoom, user: AtLeast<IUser, '_id' | 'name' | 'username' | 'roles'>): Promise<void> {
	const room = typeof roomOrId === 'string' ? await Rooms.findOneById(roomOrId) : roomOrId;

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

	if (room.federated) {
		throw new Meteor.Error('error-cannot-delete-federated-room', 'Cannot delete federated room', {
			method: 'eraseRoom',
		});
	}

	if (
		!(await roomCoordinator
			.getRoomDirectives(room.t)
			?.canBeDeleted((permissionId, rid) => hasPermissionAsync(user, permissionId, rid), room))
	) {
		throw new Meteor.Error('error-not-allowed', 'Not allowed', {
			method: 'eraseRoom',
		});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Re-fetch the room by id and confirm it still exists before issuing the delete
  2. If it was already deleted, treat the outcome as success in the caller (idempotent delete)
Defensive patterns

Strategy: validation

Validate before calling

const room = typeof roomOrId === 'string' ? await Rooms.findOneById(roomOrId) : roomOrId;
if (!room) {
  // room already gone: treat the delete as complete (idempotent) instead of calling eraseRoom
}

Type guard

const isExistingRoom = (room: IRoom | null | undefined): room is IRoom =>
  Boolean(room && room._id);

Prevention

When it happens

Trigger: Calling eraseRoom with a room id that was already deleted, an id from another deployment, a typo'd _id, or a falsy room argument.

Common situations: Two admins racing to delete the same room; UI acting on a cached room deleted elsewhere; scripts passing stale ids.

Related errors


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