{"record":{"id":"d7f221152cc71229","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-d7f221","errorCode":"error-not-allowed","errorMessage":"Not allowed","messagePattern":"Not allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts","lineNumber":23,"sourceCode":"\nimport { hasPermissionAsync } from '../../../server/lib/authorization/hasPermission';\nimport notifications from '../../../server/lib/notifications/core/lib/Notifications';\n\ntype ResponseData = {\n\tshortcut: string;\n\ttext: string;\n\tscope: string;\n\ttags?: string[];\n\tdepartmentId?: string;\n};\n\nexport const saveCannedResponse = async (\n\tuserId: string,\n\tresponseData: ResponseData,\n\t_id?: string,\n): Promise<Omit<IOmnichannelCannedResponse, '_updatedAt' | '_createdAt'> & { _createdAt?: Date }> => {\n\tif (!(await hasPermissionAsync(userId, 'save-canned-responses'))) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'saveCannedResponse' });\n\t}\n\n\tcheck(_id, Match.Maybe(String));\n\n\tcheck(responseData, {\n\t\tshortcut: String,\n\t\ttext: String,\n\t\tscope: String,\n\t\ttags: Match.Maybe([String]),\n\t\tdepartmentId: Match.Maybe(String),\n\t});\n\n\tconst canSaveAll = await hasPermissionAsync(userId, 'save-all-canned-responses');\n\tif (!canSaveAll && ['global'].includes(responseData.scope)) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed to modify canned responses on *global* scope', {\n\t\t\tmethod: 'saveCannedResponse',\n\t\t});\n\t}","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts#L5-L41","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Grant 'save-canned-responses' to the acting role (Administration > Permissions)","Hide save/create UI for users without the permission","For programmatic writes, use a service account that holds the permission"],"exampleFix":"// before\nMeteor.call('saveCannedResponse', responseData);\n\n// after\nif (!(await hasPermissionAsync(uid, 'save-canned-responses'))) {\n\tthrow new Meteor.Error('error-not-allowed', 'Not allowed');\n}\nMeteor.call('saveCannedResponse', responseData);","handlingStrategy":"validation","validationCode":"if (!(await hasPermissionAsync(userId, 'save-canned-responses'))) {\n\tthrow new Meteor.Error('error-not-allowed', 'Not allowed');\n}\nawait saveCannedResponse(userId, responseData, _id);","typeGuard":null,"tryCatchPattern":"try {\n\tawait saveCannedResponse(userId, responseData, _id);\n} catch (e) {\n\tif (e instanceof Meteor.Error && e.error === 'error-not-allowed') {\n\t\t// hide save UI for this user; permissions missing\n\t}\n\tthrow e;\n}","preventionTips":["Gate the canned-response editor on 'save-canned-responses'","Audit roles after enabling canned responses so agents get the intended permissions","For programmatic writes, provision a service account with the permission"],"tags":["canned-responses","omnichannel","permissions","meteor-method"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}