RocketChat/Rocket.Chat · warning · Meteor.Error

You_cant_leave_a_livechat_room_Please_use_the_close_button

Error message

You_cant_leave_a_livechat_room_Please_use_the_close_button

What it means

A beforeLeaveRoomCallback registered at Meteor.startup blocks the generic 'leave room' action for omnichannel rooms: if isOmnichannelRoom(room) is true it throws a Meteor.Error whose message is the translated key 'You_cant_leave_a_livechat_room_Please_use_the_close_button' (translated into the user's language). Livechat rooms are closed, not left — leaving would corrupt the agent/visitor relationship model.

Source

Thrown at apps/meteor/server/lib/omnichannel/startup.ts:77

		await ContactMerger.mergeFieldsIntoContact({
			fields,
			contact,
			conflictHandlingMode: contact.unknown ? 'overwrite' : 'conflict',
		});
	}

	return visitor;
});

Meteor.startup(async () => {
	roomCoordinator.setRoomFind('l', async (id) => maybeMigrateLivechatRoom(await LivechatRooms.findOneById(id)));

	beforeLeaveRoomCallback.add(
		(user, room) => {
			if (!isOmnichannelRoom(room)) {
				return;
			}
			throw new Meteor.Error(
				i18n.t('You_cant_leave_a_livechat_room_Please_use_the_close_button', {
					lng: user.language || settings.get('Language') || 'en',
				}),
			);
		},
		callbacks.priority.LOW,
		'cant-leave-omnichannel-room',
	);

	callbacks.add(
		'beforeJoinRoom',
		async (user, room) => {
			if (isOmnichannelRoom(room) && !(await hasPermissionAsync(user, 'view-l-room'))) {
				throw new Meteor.Error('error-user-is-not-agent', 'User is not an Omnichannel Agent', {
					method: 'beforeJoinRoom',
				});
			}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. For livechat rooms use the omnichannel close/return flows (the close button, or the room close APIs) instead of leaveRoom
  2. Guard client-side: hide/disable the leave action when room.t === 'l'
  3. If an agent should no longer handle the chat, close the conversation or transfer it — never leave
  4. Catch this specific translated error in generic leave UIs and show the proper close affordance

Example fix

// before
Meteor.call('leaveRoom', room._id); // throws for livechat rooms

// after
if (room.t === 'l') {
  // omnichannel rooms are closed, not left
  Meteor.call('livechat:closeRoom', room._id);
} else {
  Meteor.call('leaveRoom', room._id);
}
Defensive patterns

Strategy: validation

Validate before calling

// generic leave flow: branch on room type before calling leaveRoom
function canLeaveRoom(room: { t: string }): boolean {
  return room.t !== 'l'; // omnichannel rooms cannot be left, only closed
}

Type guard

function isOmnichannelRoom(v: { t?: string } | null | undefined): v is { _id: string; t: 'l' } {
  return v?.t === 'l';
}

Try / catch

try {
  await Meteor.callAsync('leaveRoom', rid);
} catch (err) {
  if (err instanceof Meteor.Error && /livechat_room/i.test(err.reason ?? '')) {
    // show 'use the close button' guidance instead of a generic error
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Any code path that ends in the 'leaveRoom' Meteor method/callback chain for a room with t: 'l' — e.g. a client calling leaveRoom on an omnichannel room, or a generic UI component reusing the channel-leave flow for livechat.

Common situations: Custom apps or UI components assuming all rooms support 'leave', users pressing a leave shortcut on a livechat conversation, or integrations calling Meteor.call('leaveRoom', rid) generically.

Related errors


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