RocketChat/Rocket.Chat · error · Error

error-invalid-room

error-invalid-room

Error message

error-invalid-room

What it means

Thrown by sendTranscript in apps/meteor/server/lib/omnichannel/sendTranscript.ts when LivechatRooms.findOneById(rid) returns null. Only livechat (omnichannel) rooms live in the LivechatRooms collection, so a missing document means the rid either does not exist or is not a livechat room. It is a plain Error (not Meteor.Error) with the code as its message.

Source

Thrown at apps/meteor/server/lib/omnichannel/sendTranscript.ts:49

export async function sendTranscript({
	token,
	rid,
	email,
	subject,
	user,
}: {
	token: string;
	rid: string;
	email: string;
	subject?: string;
	user?: Pick<IUser, '_id' | 'name' | 'username' | 'utcOffset'> | null;
}): Promise<boolean> {
	logger.debug({ msg: 'Sending conversation transcript', rid, token });

	const room = await LivechatRooms.findOneById<Pick<IOmnichannelRoom, '_id' | 'v'>>(rid, { projection: { _id: 1, v: 1 } });
	if (!room) {
		throw new Error('error-invalid-room');
	}

	const visitor = room?.v as ILivechatVisitor;
	if (token !== visitor?.token) {
		throw new Error('error-invalid-visitor');
	}

	const userLanguage = settings.get<string>('Language') || 'en';
	const timezone = getTimezone(user);
	logger.debug({ msg: 'Transcript will be sent using timezone', timezone });

	const showAgentInfo = settings.get<boolean>('Livechat_show_agent_info');
	const showSystemMessages = settings.get<boolean>('Livechat_transcript_show_system_messages');
	const closingMessage = await Messages.findLivechatClosingMessage(rid, { projection: { ts: 1 } });
	const ignoredMessageTypes: MessageTypesValues[] = [
		'livechat_navigation_history',
		'livechat_transcript_history',
		'command',

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Log/verify the rid passed to sendTranscript and confirm it is an omnichannel room id (t: 'l')
  2. Check the room still exists: db.rocketchat_room.findOne({_id: rid, t: 'l'})
  3. If the room was deleted, the transcript cannot be produced from room data — regenerate from message history only if you keep backups
  4. Fix the caller (widget/integration) to pass the rid returned by the livechat room creation API
Defensive patterns

Strategy: validation

Validate before calling

import { LivechatRooms } from '@rocket.chat/models';

const room = await LivechatRooms.findOneById(rid, { projection: { _id: 1, v: 1 } });
if (!room) {
  // fail early with your own error instead of error-invalid-room deep in sendTranscript
  throw new Error(`no livechat room ${rid}`);
}
await sendTranscript({ rid, token, email, room });

Type guard

function isLivechatRoom(v: { t?: string } | null | undefined): v is { _id: string; t: 'l'; v: { token: string } } {
  return !!v && v.t === 'l' && typeof v.v?.token === 'string';
}

Try / catch

try {
  await sendTranscript({ rid, token, email });
} catch (err) {
  if (err instanceof Error && err.message === 'error-invalid-room') {
    // room missing: surface a user-facing 'conversation not found' and stop
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling sendTranscript({ rid, token, email }) with a rid that has no document in LivechatRooms: a typo'd id, a regular channel id, a room that was already deleted, or a race where the room was removed right before the call.

Common situations: Passing a channel/group id instead of the livechat room id from the widget, transcript requested after the room was purged by retention/cleanup jobs, or truncated/copied ids in integrations.

Related errors


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