{"record":{"id":"ada8c126e9888879","repo":"RocketChat/Rocket.Chat","slug":"error-cannot-delete-app-user","errorCode":"error-cannot-delete-app-user","errorMessage":"Deleting app user is not allowed","messagePattern":"Deleting app user is not allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/users/deleteUser.ts","lineNumber":27,"sourceCode":"import { deleteUser } from '../../lib/users/deleteUser';\n\ndeclare module '@rocket.chat/ddp-client' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface ServerMethods {\n\t\tdeleteUser(userId: IUser['_id'], confirmRelinquish?: boolean): boolean;\n\t}\n}\n\nexport const executeDeleteUser = async (fromUserId: IUser['_id'], userId: IUser['_id'], confirmRelinquish = false): Promise<boolean> => {\n\tconst user = await Users.findOneById(userId);\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user to delete', {\n\t\t\tmethod: 'deleteUser',\n\t\t});\n\t}\n\n\tif (user.type === 'app') {\n\t\tthrow new Meteor.Error('error-cannot-delete-app-user', 'Deleting app user is not allowed', {\n\t\t\tmethod: 'deleteUser',\n\t\t});\n\t}\n\n\tconst adminCount = await Users.countDocuments({ roles: 'admin' });\n\n\tconst userIsAdmin = user.roles?.indexOf('admin') > -1;\n\n\tif (adminCount === 1 && userIsAdmin) {\n\t\tthrow new Meteor.Error('error-action-not-allowed', 'Leaving the app without admins is not allowed', {\n\t\t\tmethod: 'deleteUser',\n\t\t\taction: 'Remove_last_admin',\n\t\t});\n\t}\n\n\tawait deleteUser(userId, confirmRelinquish, fromUserId);\n\n\treturn true;","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/users/deleteUser.ts#L9-L45","documentation":"`executeDeleteUser` refuses to delete users whose `type === 'app'`: accounts created and owned by the Apps Engine to run apps. These service users are protected because deleting them corrupts the associated app; the correct lifecycle path is uninstalling the app, which removes its user. The check runs right after the existence check and before the last-admin guard.","triggerScenarios":"Calling `deleteUser` (or REST `DELETE /v1/users.delete`) targeting an app user — typically visible in user lists as the app's bot/service account (`type: 'app'` in the users collection).","commonSituations":"Admins trying to clean up 'strange' bot users created by installed apps; scripts that bulk-delete users without filtering by type; app users lingering in lists after a failed app installation, tempting manual removal.","solutions":["Uninstall the owning app (Admin → Apps) instead of deleting its user — the app lifecycle removes the service account.","In bulk-delete scripts, filter targets with `type !== 'app'` before calling deleteUser.","If an app user is orphaned (app already gone), remove it via the apps management path or DB cleanup with the app records together — not via this method.","Never delete app users directly from the database while the app remains installed."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"const user = await Users.findOneById(userId, { projection: { type: 1 } });\nif (user && user.type !== 'app') {\n  await deleteUserFn(uid, userId);\n}","typeGuard":"const isDeletableUserType = (user: { type?: string } | null): boolean => !!user && user.type !== 'app';","tryCatchPattern":"try {\n  await Meteor.callAsync('deleteUser', userId);\n} catch (e: any) {\n  if (e?.error === 'error-cannot-delete-app-user') {\n    // route to app uninstall instead of user deletion\n  }\n}","preventionTips":["Filter `type === 'app'` users out of bulk deletion targets.","Manage app service accounts only through app install/uninstall.","Do not hand-edit or remove app users in the database while the app is installed."],"tags":["meteor","users","delete","apps-engine","service-account"],"backgroundTag":"cannot-delete-system-account","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}