{"record":{"id":"8ede1e5d323a7f24","repo":"RocketChat/Rocket.Chat","slug":"error-app-prevented-deleting","errorCode":"error-app-prevented-deleting","errorMessage":"A Rocket.Chat App prevented the room erasing.","messagePattern":"A Rocket\\.Chat App prevented the room erasing\\.","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/eraseRoom.ts","lineNumber":46,"sourceCode":"\t\t\t.getRoomDirectives(room.t)\n\t\t\t?.canBeDeleted((permissionId, rid) => hasPermissionAsync(user, permissionId, rid), room))\n\t) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'eraseRoom',\n\t\t});\n\t}\n\n\tconst team = room.teamId && (await Team.getOneById(room.teamId, { projection: { roomId: 1 } }));\n\tif (team && !(await hasPermissionAsync(user, `delete-team-${room.t === 'c' ? 'channel' : 'group'}`, team.roomId))) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'eraseRoom',\n\t\t});\n\t}\n\n\tif (Apps.self?.isLoaded()) {\n\t\tconst prevent = await Apps.self?.triggerEvent(AppEvents.IPreRoomDeletePrevent, room);\n\t\tif (prevent) {\n\t\t\tthrow new Meteor.Error('error-app-prevented-deleting', 'A Rocket.Chat App prevented the room erasing.');\n\t\t}\n\t}\n\n\tawait deleteRoom(room._id);\n\n\tif (team) {\n\t\tawait Message.saveSystemMessage('user-deleted-room-from-team', team.roomId, room.name || '', user);\n\t}\n\n\tif (Apps.self?.isLoaded()) {\n\t\tvoid Apps.self?.triggerEvent(AppEvents.IPostRoomDeleted, room);\n\t}\n}\n","sourceCodeStart":28,"sourceCodeEnd":60,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/eraseRoom.ts#L28-L60","documentation":"Before deleting, eraseRoom triggers the Apps Engine event IPreRoomDeletePrevent; if any loaded App's handler returns a truthy value, deletion is vetoed and this error is thrown. The veto is deliberate policy from an installed App, not a server bug.","triggerScenarios":"Any installed Rocket.Chat App implementing IPreRoomDeletePrevent (retention/legal-hold, DLP, archival apps) returns true when eraseRoom is called for a room it wants to keep.","commonSituations":"Compliance apps intentionally blocking deletion of retained rooms; an app bug vetoing every delete; app updated with stricter room filters.","solutions":["Identify the vetoing App: review installed Apps and which ones listen to IPreRoomDeletePrevent","Adjust the App's configuration/room filters so this room may be deleted, or disable/uninstall the App if the veto is unwanted","Contact the App maintainer if the veto looks unintentional"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await eraseRoom(roomId, user);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-app-prevented-deleting') {\n    // an installed App vetoed the delete: inform the user, do not retry\n    return;\n  }\n  throw err;\n}","preventionTips":["Audit which installed Apps hook IPreRoomDeletePrevent before running bulk-delete tooling","Surface app vetoes explicitly in the UI instead of a generic failure","Treat this error as policy, not a bug: retrying will not help"],"tags":["apps","apps-engine","rooms","deletion"],"backgroundTag":"app-hook-veto","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}