RocketChat/Rocket.Chat · error · Error

invalid-room

invalid-room

Error message

invalid-room

What it means

Thrown by GET /api/v1/livechat/:rid/messages (requires auth plus the view-l-room permission) when LivechatRooms.findOneById(rid) returns null — the URL segment is not the _id of an existing livechat room. The endpoint lists a livechat room's closed/session messages, so passing a regular channel/group rid, a deleted room's rid, or a malformed id fails this lookup before any access check runs.

Solutions

  1. Source rids only from livechat APIs: GET /api/v1/livechat/rooms (agent view) or the visitor's own history endpoints, never channels.list
  2. Sanity-check the rid shape before calling — Rocket.Chat ids are 17-character alphanumeric strings
  3. If rooms can vanish underneath you (retention), catch this error and drop the rid from your cache instead of retrying

Example fix

// before
const { messages } = await sdk.get(`livechat/${rid}/messages`);

// after (validate rid shape, then call)
if (!/^[A-Za-z0-9]{17}$/.test(rid)) throw new Error(`malformed rid: ${rid}`);
const { messages } = await sdk.get(`livechat/${rid}/messages`);
Defensive patterns

Strategy: validation

Validate before calling

const isValidRid = (rid: string) => /^[A-Za-z0-9]{17}$/.test(rid);
if (!isValidRid(rid)) throw new Error(`malformed rid: ${JSON.stringify(rid)}`);
// prefer sourcing rids from livechat data:
const { rooms } = await sdk.get('livechat/rooms', { count: 1 }); // rooms the agent can access

Type guard

const isLivechatRoomId = (rid: unknown): rid is string =>
  typeof rid === 'string' && /^[A-Za-z0-9]{17}$/.test(rid);

Try / catch

catch error 'invalid-room' and evict the rid from your local cache/queue — the room is gone or was never a livechat room; retrying with the same id cannot succeed.

Prevention

When it happens

Trigger: GET /api/v1/livechat/<rid>/messages where rid is a typo'd or truncated 17-char id, the _id of a normal channel or private group instead of a livechat room, or the id of a livechat room that was deleted (retention/pruning or omnichannel cleanup).

Common situations: Reusing rids captured in a different environment; copy-pasting a message id or visitor token into the rid slot; room disappeared between listing it and fetching messages; code that assumes any room id works for livechat endpoints.

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@2a7de45707 (2026-08-18). Data as JSON: /api/errors/a81eed22104211ae. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/server/api/v1/omnichannel/visitors.ts:178

				}),
			);
		},
	},
);

API.v1.addRoute(
	'livechat/:rid/messages',
	{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLivechatRidMessagesProps },
	{
		async get() {
			const { offset, count } = await getPaginationItems(this.queryParams);
			const { sort } = await this.parseJsonQuery();
			const { searchTerm } = this.queryParams;

			const room = await LivechatRooms.findOneById(this.urlParams.rid);

			if (!room) {
				throw new Error('invalid-room');
			}

			if (!(await canAccessRoomAsync(room, this.user))) {
				throw new Error('not-allowed');
			}

			const { cursor, totalCount } = Messages.findLivechatClosedMessages(this.urlParams.rid, searchTerm, {
				sort: sort || { ts: -1 },
				skip: offset,
				limit: count,
			});

			const [messages, total] = await Promise.all([cursor.toArray(), totalCount]);

			return API.v1.success({
				messages: await normalizeMessagesForUser(messages, this.userId),
				offset,
				count,

View on GitHub (pinned to 2a7de45707)