RocketChat/Rocket.Chat · error · Error

error-not-authorized

error-not-authorized

Error message

error-not-authorized

What it means

Before closing an omnichannel room, closeLivechatRoom checks that the closing user either has a subscription in that room or holds the 'close-others-livechat-room' permission (checked asynchronously via hasPermissionAsync); otherwise it throws Error('error-not-authorized'). This guards against users closing chats they are not participating in.

Source

Thrown at apps/meteor/server/lib/omnichannel/closeLivechatRoom.ts:39

		transcriptEmail?:
			| {
					sendToVisitor: false;
			  }
			| {
					sendToVisitor: true;
					requestData: Pick<NonNullable<IOmnichannelRoom['transcriptRequest']>, 'email' | 'subject'>;
			  };
		forceClose?: boolean;
	},
): Promise<void> => {
	const room = await LivechatRooms.findOneById(roomId);
	if (!room) {
		throw new Error('error-invalid-room');
	}

	const subscription = await Subscriptions.findOneByRoomIdAndUserId(roomId, user._id, { projection: { _id: 1 } });
	if (!subscription && !(await hasPermissionAsync(user, 'close-others-livechat-room'))) {
		throw new Error('error-not-authorized');
	}

	const options: CloseRoomParams['options'] = {
		clientAction: true,
		tags,
		...(generateTranscriptPdf && { pdfTranscript: { requestedBy: user._id } }),
		...(transcriptEmail && {
			...(transcriptEmail.sendToVisitor
				? {
						emailTranscript: {
							sendToVisitor: true,
							requestData: {
								email: transcriptEmail.requestData.email,
								subject: transcriptEmail.requestData.subject,
								requestedAt: new Date(),
								requestedBy: user,
							},
						},

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Grant 'close-others-livechat-room' to the role of any user who must close other agents' chats
  2. Close the room as its serving agent (the user in room.servedBy), who has a subscription
  3. Invoke the close API with a user that actually participated in the room
  4. Re-audit role-permission sets after upgrades so omnichannel close permissions survive
Defensive patterns

Strategy: validation

Validate before calling

import { Subscriptions } from '@rocket.chat/models';
import { hasPermissionAsync } from '../../../authorization/server';

// Can this user close this room?
const sub = await Subscriptions.findOneByRoomIdAndUserId(roomId, user._id, { projection: { _id: 1 } });
const allowed = !!sub || (await hasPermissionAsync(user._id, 'close-others-livechat-room'));
if (!allowed) {
  // close as the serving agent instead, or grant the permission first
}

Try / catch

try {
  await closeLivechatRoom(roomId, user, { clientAction: true });
} catch (err: any) {
  if (err?.message === 'error-not-authorized') return respondForbidden('close-others-livechat-room required');
  throw err;
}

Prevention

When it happens

Trigger: A livechat manager or admin without 'close-others-livechat-room' calls closeLivechatRoom on a room they never served; a bot/integration user closes rooms it has no subscription for; the closing user id belongs to a different workspace.

Common situations: Custom roles cloned from agent that lost the permission after an upgrade reshuffled role definitions; bulk-close scripts running as a service user with no room subscriptions; permissions removed during an admin audit.

Related errors


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