{"record":{"id":"c64477a48e0a1be3","repo":"RocketChat/Rocket.Chat","slug":"error-action-not-allowed-c64477","errorCode":"error-action-not-allowed","errorMessage":"Editing settings is not allowed","messagePattern":"Editing settings is not allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/settings/lib/saveSettingsBulk.ts","lineNumber":110,"sourceCode":"\t\t\t\t\tbreak;\n\t\t\t\tcase 'multiSelect':\n\t\t\t\t\tcheck(value, Array);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'code':\n\t\t\t\t\tcheck(value, String);\n\t\t\t\t\tif (isSettingCode(setting) && setting.code === 'application/json') {\n\t\t\t\t\t\tcheck(value, validJSON);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcheck(value, String);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}),\n\t);\n\n\tif (settingsNotAllowed.length) {\n\t\tthrow new Meteor.Error('error-action-not-allowed', 'Editing settings is not allowed', {\n\t\t\tmethod: 'saveSettings',\n\t\t\tsettingIds: settingsNotAllowed,\n\t\t});\n\t}\n\n\tvalidateSettingRules(params);\n\n\tconst auditSettingOperation = updateAuditedByUser({\n\t\t_id: uid,\n\t\tusername: audit.username,\n\t\tip: audit.ip,\n\t\tuseragent: audit.useragent,\n\t});\n\n\tconst promises = params.map(async ({ _id, value, editor }) => {\n\t\tconst valueResult = await auditSettingOperation(Settings.updateValueById, _id, value);\n\n\t\tif (!editor) {","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/settings/lib/saveSettingsBulk.ts#L92-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run the save with a user that has edit-privileged-setting (or manage-selected-settings plus the specific setting's permission)","Remove Custom_Script_* ids from the payload on workspaces that block custom scripts","Read error.details.settingIds to see exactly which ids were rejected and split them out of the bulk update","Have an admin perform privileged settings changes through the admin UI instead"],"exampleFix":"// before\nawait POST('/api/v1/settings', [{ _id: 'Custom_Script_Logged_Out', value: '<script>...' }]);\n// -> error-action-not-allowed, settingIds: ['Custom_Script_Logged_Out']\n\n// after - authenticate with edit-privileged-setting and drop blocked ids\nconst allowed = params.filter(({ _id }) => !blockedIds.includes(_id));\nawait POST('/api/v1/settings', allowed);","handlingStrategy":"validation","validationCode":"const canEditPrivileged = await hasPermissionAsync(uid, 'edit-privileged-setting');\nconst canManageSelected = await hasPermissionAsync(uid, 'manage-selected-settings');\nif (!canEditPrivileged && !canManageSelected) {\n\tthrow new Meteor.Error('forbidden', 'Use an account with edit-privileged-setting');\n}\nconst safeParams = params.filter(({ _id }) => !disableCustomScripts() || !/^Custom_Script_/.test(_id));\nawait saveSettingsBulk(uid, safeParams, audit);","typeGuard":null,"tryCatchPattern":"catch (err) {\n\tif (err instanceof Meteor.Error && err.error === 'error-action-not-allowed') {\n\t\tconst blocked = err.details?.settingIds ?? [];\n\t\t// remove blocked ids, escalate to a privileged user, or use the admin UI\n\t} else throw err;\n}","preventionTips":["Use a privileged account (edit-privileged-setting) for settings automation","Never include Custom_Script_* ids in payloads on cloud workspaces","Split bulk saves so blocked settings fail alone, not the whole batch"],"tags":["settings","permissions","authorization","cloud","meteor-method"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}