RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

Not allowed

What it means

saveCannedResponse (apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts:23) requires the base 'save-canned-responses' permission via hasPermissionAsync; without it the call fails immediately with error-not-allowed before any argument validation runs.

Solutions

  1. Grant 'save-canned-responses' to the acting role (Administration > Permissions)
  2. Hide save/create UI for users without the permission
  3. For programmatic writes, use a service account that holds the permission

Example fix

// before
Meteor.call('saveCannedResponse', responseData);

// after
if (!(await hasPermissionAsync(uid, 'save-canned-responses'))) {
	throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
Meteor.call('saveCannedResponse', responseData);
Defensive patterns

Strategy: validation

Validate before calling

if (!(await hasPermissionAsync(userId, 'save-canned-responses'))) {
	throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
await saveCannedResponse(userId, responseData, _id);

Try / catch

try {
	await saveCannedResponse(userId, responseData, _id);
} catch (e) {
	if (e instanceof Meteor.Error && e.error === 'error-not-allowed') {
		// hide save UI for this user; permissions missing
	}
	throw e;
}

Prevention

When it happens

Trigger: Calling saveCannedResponse with a userId lacking the 'save-canned-responses' permission — e.g. livechat agents without canned-response rights, or bots/integrations acting as unprivileged users.

Common situations: Canned responses enabled for the workspace but the agent's role was never granted the permission; permission set changed by an admin; custom automation using a plain user account.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts:23

import { hasPermissionAsync } from '../../../server/lib/authorization/hasPermission';
import notifications from '../../../server/lib/notifications/core/lib/Notifications';

type ResponseData = {
	shortcut: string;
	text: string;
	scope: string;
	tags?: string[];
	departmentId?: string;
};

export const saveCannedResponse = async (
	userId: string,
	responseData: ResponseData,
	_id?: string,
): Promise<Omit<IOmnichannelCannedResponse, '_updatedAt' | '_createdAt'> & { _createdAt?: Date }> => {
	if (!(await hasPermissionAsync(userId, 'save-canned-responses'))) {
		throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'saveCannedResponse' });
	}

	check(_id, Match.Maybe(String));

	check(responseData, {
		shortcut: String,
		text: String,
		scope: String,
		tags: Match.Maybe([String]),
		departmentId: Match.Maybe(String),
	});

	const canSaveAll = await hasPermissionAsync(userId, 'save-all-canned-responses');
	if (!canSaveAll && ['global'].includes(responseData.scope)) {
		throw new Meteor.Error('error-not-allowed', 'Not allowed to modify canned responses on *global* scope', {
			method: 'saveCannedResponse',
		});
	}

View on GitHub (pinned to b2c16d5842)