RocketChat/Rocket.Chat · error · Error

invalid-room

Error message

invalid-room

What it means

Thrown in the GET handler of 'livechat/room' (room.ts:118-121) when LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {}) returns null. This executes only when a rid IS provided in the query params (the !rid branch at line 80 handles room creation/lookup without rid). The query finds an OPEN room matching both the rid and the visitor token.

Source

Thrown at apps/meteor/server/api/v1/omnichannel/room.ts:120

					},
				};

				const newRoom = await createRoom({
					visitor: guest,
					roomInfo,
					agent,
					extraData: extraParams as IOmnichannelInquiryExtraData,
				});

				return API.v1.success({
					room: newRoom,
					newRoom: true,
				});
			}

			const froom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token, {});
			if (!froom) {
				throw new Error('invalid-room');
			}

			return API.v1.success({ room: froom, newRoom: false });
		},
	},
);

// Note: use this route if a visitor is closing a room
// If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route
API.v1.addRoute(
	'livechat/room.close',
	{ validateParams: isPOSTLivechatRoomCloseParams },
	{
		async post() {
			const { rid, token } = this.bodyParams;

			if (!rcSettings.get('Omnichannel_allow_visitors_to_close_conversation')) {
				throw new Error('error-not-allowed-to-close-conversation');

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Check if the room exists (including closed): db.livechat_rooms.findOne({_id: rid}).
  2. Check if it belongs to this visitor: db.livechat_rooms.findOne({_id: rid, 'v.token': token}).
  3. Check if it's open: db.livechat_rooms.findOne({_id: rid, open: true}). If closed, a new room must be created.
  4. If no rid is provided, the handler will create or find an open room automatically — omit rid to get a new room.

Example fix

// before
GET /api/v1/livechat/room?token=X&rid=closedRoomId
// throws 'invalid-room' because the room is closed

// after — omit rid to let the system find/create an open room
GET /api/v1/livechat/room?token=X
Defensive patterns

Strategy: validation

Validate before calling

// Check for an open room before requesting it by rid
const openRoom = await LivechatRooms.findOneOpenByRoomIdAndVisitorToken(rid, token);
if (!openRoom) {
  // omit rid to let the system find/create an open room instead
  throw new Error(`No open room ${rid} for this visitor — create a new one instead`);
}

Type guard

function isOpenRoomForVisitor(room: IOmnichannelRoom | null, token: string): room is IOmnichannelRoom {
  return room !== null && room.open === true && room.v?.token === token;
}

Try / catch

try {
  await api.get(`/livechat/room?token=${token}&rid=${rid}`);
} catch (err) {
  if (err.message === 'invalid-room') {
    // omit rid to find/create an open room
    await api.get(`/livechat/room?token=${token}`);
  }
}

Prevention

When it happens

Trigger: Calling GET /api/v1/livechat/room?token=X&rid=Y where no open livechat room with _id=Y is associated with visitor token X. The room may be closed, may not exist, or may belong to a different visitor.

Common situations: The room was already closed by the visitor or an agent; rid is from a different visitor's session; rid was mistyped; the room was deleted. Note this specifically looks for OPEN rooms — a closed room will return null even if it exists.

Related errors


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