RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room

error-invalid-room

Error message

error-invalid-room

What it means

removeOmnichannelRoom(rid) loads the room via LivechatRooms.findOneById; a null lookup throws Meteor.Error('error-invalid-room', 'Invalid room') as the first guard, before any type or state validation.

Source

Thrown at apps/meteor/server/lib/omnichannel/rooms.ts:275

	try {
		await saveTransferHistory(room, transferData);
		await RoutingManager.unassignAgent(inquiry, departmentId);
	} catch (err) {
		livechatLogger.error({ err });
		throw new Meteor.Error('error-returning-inquiry');
	}

	callbacks.runAsync('livechat:afterReturnRoomAsInquiry', { room });

	return true;
}

export async function removeOmnichannelRoom(rid: string) {
	livechatLogger.debug({ msg: 'Deleting room', roomId: rid });
	check(rid, String);
	const room = await LivechatRooms.findOneById(rid);
	if (!room) {
		throw new Meteor.Error('error-invalid-room', 'Invalid room');
	}

	if (!isOmnichannelRoom(room)) {
		throw new Meteor.Error('error-this-is-not-a-livechat-room');
	}

	if (room.open) {
		throw new Meteor.Error('error-room-is-not-closed');
	}

	const inquiry = await LivechatInquiry.findOneByRoomId(rid);

	const result = await Promise.allSettled([
		Messages.removeByRoomId(rid),
		ReadReceipts.removeByRoomId(rid),
		Subscriptions.removeByRoomId(rid, {
			async onTrash(doc) {
				void notifyOnSubscriptionChanged(doc, 'removed');

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Verify the room exists (e.g., GET /api/v1/rooms.info) before deleting.
  2. Treat 'error-invalid-room' on retry as success for idempotent deletion workflows.
  3. Re-fetch the rid at deletion time instead of caching it long-term.

Example fix

// before
await removeOmnichannelRoom(rid); // throws error-invalid-room

// after
if (!(await LivechatRooms.findOneById(rid, { projection: { _id: 1 } }))) {
	// already gone - treat as success for idempotent deletion
	return;
}
await removeOmnichannelRoom(rid);
Defensive patterns

Strategy: validation

Validate before calling

if (!(await LivechatRooms.findOneById(rid, { projection: { _id: 1 } }))) {
	// room already gone: treat as success for idempotent deletion
	return;
}
await removeOmnichannelRoom(rid);

Type guard

const isExistingRoom = async (rid: string): Promise<boolean> =>
	Boolean(await LivechatRooms.findOneById(rid, { projection: { _id: 1 } }));

Try / catch

try {
	await removeOmnichannelRoom(rid);
} catch (err) {
	if (err instanceof Meteor.Error && err.error === 'error-invalid-room') {
		// already removed or wrong rid: refresh the source of rids
		return;
	}
	throw err;
}

Prevention

When it happens

Trigger: Calling removeOmnichannelRoom with a rid that does not exist — typo, room already removed, or a client acting on a stale cached id.

Common situations: Deletion retried after success; rid copied from the wrong field; room already purged by a retention job.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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