{"record":{"id":"bf7d95932ffecbde","repo":"RocketChat/Rocket.Chat","slug":"error-canned-response-not-found","errorCode":"error-canned-response-not-found","errorMessage":"Canned Response not found","messagePattern":"Canned Response not found","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/meteor-methods/removeCannedResponse.ts","lineNumber":19,"sourceCode":"import { CannedResponse } from '@rocket.chat/models';\nimport { check } from 'meteor/check';\nimport { Meteor } from 'meteor/meteor';\n\nimport { hasPermissionAsync } from '../../../server/lib/authorization/hasPermission';\nimport notifications from '../../../server/lib/notifications/core/lib/Notifications';\n\nexport const removeCannedResponse = async (uid: string, _id: string): Promise<void> => {\n\tif (!(await hasPermissionAsync(uid, 'remove-canned-responses'))) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'removeCannedResponse',\n\t\t});\n\t}\n\n\tcheck(_id, String);\n\n\tconst cannedResponse = await CannedResponse.findOneById(_id);\n\tif (!cannedResponse) {\n\t\tthrow new Meteor.Error('error-canned-response-not-found', 'Canned Response not found', {\n\t\t\tmethod: 'removeCannedResponse',\n\t\t});\n\t}\n\n\tnotifications.streamCannedResponses.emit('canned-responses', { type: 'removed', _id });\n\n\tawait CannedResponse.removeById(_id);\n};\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/meteor-methods/removeCannedResponse.ts#L1-L28","documentation":"Thrown by removeCannedResponse (removeCannedResponse.ts:19) after the permission check: CannedResponse.findOneById(_id) returns null, so there is nothing to remove. The id passed does not match any canned response document.","triggerScenarios":"Deleting a canned response that was already deleted by another user/session, or passing a wrong/truncated _id (check(_id, String) only enforces the type).","commonSituations":"Stale list in another agent's UI after concurrent deletion; id mangled by client code; canned responses wiped by re-import or workspace copy where ids diverged.","solutions":["Refresh the canned response list and retry with a current id","Treat error-canned-response-not-found as success in idempotent delete flows (goal already achieved)","Verify the id originates from a fresh CannedResponse.find query"],"exampleFix":"// before\nawait removeCannedResponse(uid, _id);\n\n// after\nconst existing = await CannedResponse.findOneById(_id, { projection: { _id: 1 } });\nif (!existing) {\n\treturn; // already removed — treat as deleted\n}\nawait removeCannedResponse(uid, _id);","handlingStrategy":"validation","validationCode":"const existing = await CannedResponse.findOneById(_id, { projection: { _id: 1 } });\nif (!existing) {\n\t// already removed or unknown id — treat as deleted\n\treturn;\n}\nawait removeCannedResponse(uid, _id);","typeGuard":null,"tryCatchPattern":"try {\n\tawait removeCannedResponse(uid, _id);\n} catch (e) {\n\tif (e instanceof Meteor.Error && e.error === 'error-canned-response-not-found') {\n\t\t// idempotent delete: already gone — refresh the list and move on\n\t\treturn;\n\t}\n\tthrow e;\n}","preventionTips":["Refresh the canned-response list before acting on records loaded long ago","Treat not-found on delete as success in idempotent flows","Always use ids from a fresh query, never reconstructed strings"],"tags":["canned-responses","not-found","omnichannel","meteor-method"],"backgroundTag":"resource-not-found","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"}