{"record":{"id":"b11f7973f6647c9d","repo":"RocketChat/Rocket.Chat","slug":"error-app-prevented-deleting-b11f79","errorCode":"error-app-prevented-deleting","errorMessage":"A Rocket.Chat App prevented the message deleting.","messagePattern":"A Rocket\\.Chat App prevented the message deleting\\.","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/messages/deleteMessage.ts","lineNumber":42,"sourceCode":"\tif (!originalMessage || !user || !(await canDeleteMessageAsync(user, originalMessage))) {\n\t\tthrow new Meteor.Error('error-action-not-allowed', 'Not allowed');\n\t}\n\n\treturn deleteMessage(originalMessage, user);\n};\n\nexport async function deleteMessage(message: IMessage, user: IUser): Promise<void> {\n\tconst deletedMsg: IMessage | null = await Messages.findOneById(message._id);\n\tconst isThread = (deletedMsg?.tcount || 0) > 0;\n\tconst keepHistory = settings.get('Message_KeepHistory') || isThread;\n\tconst showDeletedStatus = settings.get('Message_ShowDeletedStatus') || isThread;\n\n\tconst room = await Rooms.findOneById(message.rid, { projection: { lastMessage: 1, prid: 1, mid: 1, federated: 1, federation: 1 } });\n\n\tif (deletedMsg) {\n\t\tconst prevent = await Apps.self?.triggerEvent(AppEvents.IPreMessageDeletePrevent, deletedMsg);\n\t\tif (prevent) {\n\t\t\tthrow new Meteor.Error('error-app-prevented-deleting', 'A Rocket.Chat App prevented the message deleting.');\n\t\t}\n\n\t\tif (room) {\n\t\t\tawait Message.beforeDelete(deletedMsg, room);\n\t\t}\n\t}\n\n\tif (deletedMsg && isThreadMessage(deletedMsg)) {\n\t\tawait deleteThreadMessage(deletedMsg, user, room);\n\t}\n\n\tconst files = (message.files || [message.file]).filter(Boolean); // Keep compatibility with old messages\n\n\tif (keepHistory) {\n\t\tif (showDeletedStatus) {\n\t\t\t// TODO is there a better way to tell TS \"IUser[username]\" is not undefined?\n\t\t\tawait Messages.cloneAndSaveAsHistoryById(message._id, user as Required<Pick<IUser, '_id' | 'username' | 'name'>>);\n\t\t} else {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/messages/deleteMessage.ts#L24-L60","documentation":"deleteMessage (deleteMessage.ts:38-44) fires the Apps Engine IPreMessageDeletePrevent event before deleting. If an installed app returns a truthy 'prevent' result, the server aborts with error-app-prevented-deleting 'A Rocket.Chat App prevented the message deleting.' This is deliberate app-side policy (e.g. retention/legal hold, moderation apps), not a bug.","triggerScenarios":"An app implementing IPreMessageDeletePrevent (retention hold, audit, anti-abuse) returning true for the message being deleted; deleting messages inside a room covered by such an app's rules; app regression causing it to prevent all deletions.","commonSituations":"Compliance installs with retention apps holding messages; moderation apps blocking deletes of flagged content; admins unaware an installed app intercepts deletes; app authors accidentally returning truthy values from the hook.","solutions":["Check Administration > Apps for apps registering IPreMessageDeletePrevent and read their rules/logs to see why this message is protected","Delete via the app's own escape hatch if it provides one (e.g. a moderator command), or remove/relax the app policy","If the prevention is unintended, disable the app and retry the deletion","If you author the app, only return true deliberately and log the reason alongside"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await deleteMessage(message, user);\n} catch (error: any) {\n  if (error instanceof Meteor.Error && error.error === 'error-app-prevented-deleting') {\n    showAppProtectedMessage(); // an App holds this message; do not retry\n    return;\n  }\n  throw error;\n}","preventionTips":["Know which installed apps register IPreMessageDeletePrevent","Give users a UI hint when a retention/hold app protects messages","Do not auto-retry this error - it is a deliberate block"],"tags":["messages","delete","apps-engine","app-hook","app-prevented"],"backgroundTag":"apps-engine-blocked-action","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}