RocketChat/Rocket.Chat · error · Meteor.Error

error-action-not-allowed

error-action-not-allowed

Error message

Editing settings is not allowed

What it means

saveSettingsBulk collects ids the caller may not edit and, if any exist, fails the whole save with 'error-action-not-allowed'. Two gates push ids into settingsNotAllowed: (1) the caller lacks edit-privileged-setting AND does not have manage-selected-settings plus the per-setting permission (getSettingPermissionId(_id)); (2) on deployments where custom scripts are disabled (cloud trials), any Custom_Script_* setting is blocked to prevent phishing injections. The rejected ids come back in the error details as settingIds.

Source

Thrown at apps/meteor/server/settings/lib/saveSettingsBulk.ts:110

					break;
				case 'multiSelect':
					check(value, Array);
					break;
				case 'code':
					check(value, String);
					if (isSettingCode(setting) && setting.code === 'application/json') {
						check(value, validJSON);
					}
					break;
				default:
					check(value, String);
					break;
			}
		}),
	);

	if (settingsNotAllowed.length) {
		throw new Meteor.Error('error-action-not-allowed', 'Editing settings is not allowed', {
			method: 'saveSettings',
			settingIds: settingsNotAllowed,
		});
	}

	validateSettingRules(params);

	const auditSettingOperation = updateAuditedByUser({
		_id: uid,
		username: audit.username,
		ip: audit.ip,
		useragent: audit.useragent,
	});

	const promises = params.map(async ({ _id, value, editor }) => {
		const valueResult = await auditSettingOperation(Settings.updateValueById, _id, value);

		if (!editor) {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Run the save with a user that has edit-privileged-setting (or manage-selected-settings plus the specific setting's permission)
  2. Remove Custom_Script_* ids from the payload on workspaces that block custom scripts
  3. Read error.details.settingIds to see exactly which ids were rejected and split them out of the bulk update
  4. Have an admin perform privileged settings changes through the admin UI instead

Example fix

// before
await POST('/api/v1/settings', [{ _id: 'Custom_Script_Logged_Out', value: '<script>...' }]);
// -> error-action-not-allowed, settingIds: ['Custom_Script_Logged_Out']

// after - authenticate with edit-privileged-setting and drop blocked ids
const allowed = params.filter(({ _id }) => !blockedIds.includes(_id));
await POST('/api/v1/settings', allowed);
Defensive patterns

Strategy: validation

Validate before calling

const canEditPrivileged = await hasPermissionAsync(uid, 'edit-privileged-setting');
const canManageSelected = await hasPermissionAsync(uid, 'manage-selected-settings');
if (!canEditPrivileged && !canManageSelected) {
	throw new Meteor.Error('forbidden', 'Use an account with edit-privileged-setting');
}
const safeParams = params.filter(({ _id }) => !disableCustomScripts() || !/^Custom_Script_/.test(_id));
await saveSettingsBulk(uid, safeParams, audit);

Try / catch

catch (err) {
	if (err instanceof Meteor.Error && err.error === 'error-action-not-allowed') {
		const blocked = err.details?.settingIds ?? [];
		// remove blocked ids, escalate to a privileged user, or use the admin UI
	} else throw err;
}

Prevention

When it happens

Trigger: A non-admin or a role without edit-privileged-setting saving privileged settings via the API; any attempt to update Custom_Script_* settings on a cloud workspace where custom scripts are disabled; automation using a low-privilege user token for settings writes.

Common situations: Scripts with regular user tokens hitting saveSettings; cloud or enterprise trials hardening script settings; permission drift after role changes removed edit-privileged-setting from an admin role.

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/c64477a48e0a1be3. Report an issue: GitHub.