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
- Verify the room exists (e.g., GET /api/v1/rooms.info) before deleting.
- Treat 'error-invalid-room' on retry as success for idempotent deletion workflows.
- 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
- Confirm the room exists (rooms.info) before issuing a delete.
- Make deletion workflows idempotent: 'not found' equals success.
- Do not cache rids for later deletion; re-resolve them at operation time.
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.