RocketChat/Rocket.Chat · error · Error

error-not-allowed-to-close-conversation

Error message

error-not-allowed-to-close-conversation

What it means

Thrown by POST /api/v1/livechat/room.close when the server setting Omnichannel_allow_visitors_to_close_conversation is false. This is a configuration gate evaluated before any token/room validation — visitors are simply not permitted to end conversations through this endpoint. Admins/agents must instead use livechat/room.closeByUser, which is user-authenticated.

Solutions

  1. Enable 'Allow visitors to close conversations' (Omnichannel_allow_visitors_to_close_conversation) in Administration > Workspace > Omnichannel settings if visitors should close chats.
  2. If closure must stay agent-only, hide the visitor close button and use POST /api/v1/livechat/room.closeByUser with an authenticated user and hasPermission for closing.
  3. Have the client read the livechat init settings (visitorsCanCloseChat in GET livechat/config) and only show the close affordance when true.

Example fix

// before (close button always shown)
<button onClick={() => sdk.post('livechat/room.close', { rid, token })}>End chat</button>

// after (respect the server setting surfaced via livechat config)
const { settings } = await (await fetch('/api/v1/livechat/config')).json();
{settings.visitorsCanCloseChat && (
  <button onClick={() => sdk.post('livechat/room.close', { rid, token })}>End chat</button>
)}
Defensive patterns

Strategy: validation

Validate before calling

// Read the capability from livechat config before showing the close button
const cfg = await (await fetch('/api/v1/livechat/config')).json();
const visitorsCanClose: boolean = cfg.settings?.visitorsCanCloseChat === true;
if (visitorsCanClose) renderCloseButton();

Try / catch

if (isLivechatErrorResponse(body) && body.error === 'error-not-allowed-to-close-conversation') {
  hideCloseButton(); // server forbids visitor closure; do not retry
  showNotice('This chat can only be ended by an agent.');
}

Prevention

When it happens

Trigger: POST /api/v1/livechat/room.close with { rid, token } on a workspace where the setting is disabled (Administration > Omnichannel > 'Allow visitors to close conversations' off). It fires regardless of token validity, since the check comes first.

Common situations: Fresh installs or locked-down enterprise workspaces where admins deliberately keep closure agent-controlled; a widget shipped with a 'close chat' button deployed against a server that disallows visitor closure; settings reset during migration.

Related errors


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

Appendix: source

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

				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');
			}

			const visitor = await findGuest(token);
			if (!visitor) {
				throw new Error('invalid-token');
			}

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

			if (!room.open) {
				throw new Error('room-closed');
			}

			const language = rcSettings.get<string>('Language') || 'en';
			const comment = i18n.t('Closed_by_visitor', { lng: language });

View on GitHub (pinned to b2c16d5842)