{"record":{"id":"c9676ddb5a1e076e","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-shortcut","errorCode":"error-invalid-shortcut","errorMessage":"Shortcut provided already exists","messagePattern":"Shortcut provided already exists","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts","lineNumber":61,"sourceCode":"\tconst canSaveDepartment = await hasPermissionAsync(userId, 'save-department-canned-responses');\n\tif (!canSaveAll && !canSaveDepartment && ['department'].includes(responseData.scope)) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed to modify canned responses on *department* scope', {\n\t\t\tmethod: 'saveCannedResponse',\n\t\t});\n\t}\n\n\t// to avoid inconsistencies\n\tif (responseData.scope === 'user') {\n\t\tdelete responseData.departmentId;\n\t}\n\t// TODO: check if the department i'm trying to save is a department i can interact with\n\n\t// check if the response already exists and we're not updating one\n\tconst duplicateShortcut = await CannedResponse.findOneByShortcut(responseData.shortcut, {\n\t\tprojection: { _id: 1 },\n\t});\n\tif ((!_id && duplicateShortcut) || (_id && duplicateShortcut && duplicateShortcut._id !== _id)) {\n\t\tthrow new Meteor.Error('error-invalid-shortcut', 'Shortcut provided already exists', {\n\t\t\tmethod: 'saveCannedResponse',\n\t\t});\n\t}\n\n\tif (responseData.scope === 'department' && !responseData.departmentId) {\n\t\tthrow new Meteor.Error('error-invalid-department', 'Invalid department', {\n\t\t\tmethod: 'saveCannedResponse',\n\t\t});\n\t}\n\n\tif (\n\t\tresponseData.departmentId &&\n\t\t!(await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id'>>(responseData.departmentId, { projection: { _id: 1 } }))\n\t) {\n\t\tthrow new Meteor.Error('error-invalid-department', 'Invalid department', {\n\t\t\tmethod: 'saveCannedResponse',\n\t\t});\n\t}","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/meteor-methods/saveCannedResponse.ts#L43-L79","documentation":"saveCannedResponse (saveCannedResponse.ts:61) enforces shortcut uniqueness across the whole CannedResponse collection: CannedResponse.findOneByShortcut must not find an existing document (or, on update, must find the same _id). Creating a response with a shortcut that already exists, or updating one to a shortcut owned by a different response, throws error-invalid-shortcut.","triggerScenarios":"Creating a canned response whose shortcut collides with an existing one in any scope (user/department/global — the lookup is not scope-filtered); or updating response A to the shortcut currently used by response B (duplicateShortcut._id !== _id).","commonSituations":"Two agents independently pick !hello; import/migration scripts inserting duplicate shortcuts; renaming an existing response's shortcut to a taken value; department-specific intent foiled by the global uniqueness rule.","solutions":["Pick a different, unique shortcut (e.g. prefix it: !dept-hello)","On update, either keep the current shortcut or verify the target shortcut is free","Pre-check with CannedResponse.findOneByShortcut before submitting the form and surface the conflict early"],"exampleFix":"// before\nconst responseData = { shortcut: '!hello', text: 'Hi!', scope: 'user' };\nawait saveCannedResponse(uid, responseData);\n\n// after\nconst dup = await CannedResponse.findOneByShortcut(responseData.shortcut, { projection: { _id: 1 } });\nif (dup && dup._id !== _id) {\n\tthrow new Meteor.Error('error-invalid-shortcut', 'Shortcut provided already exists');\n}\nawait saveCannedResponse(uid, responseData);","handlingStrategy":"validation","validationCode":"const duplicate = await CannedResponse.findOneByShortcut(responseData.shortcut, { projection: { _id: 1 } });\nif ((!_id && duplicate) || (_id && duplicate && duplicate._id !== _id)) {\n\tthrow new Meteor.Error('error-invalid-shortcut', 'Shortcut provided already exists');\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-invalid-shortcut') {\n\t\t// prompt for a different shortcut; uniqueness is collection-wide\n\t}\n\tthrow e;\n}","preventionTips":["Check shortcut uniqueness while the user types and before submit","Namespace shortcuts per team/department (e.g. !sales-hello) to avoid collisions","Remember uniqueness spans all scopes, including other users' responses"],"tags":["canned-responses","omnichannel","duplicate","shortcut","uniqueness"],"backgroundTag":"duplicate-key-conflict","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"}