{"record":{"id":"49c5f706cd02ff5c","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-49c5f7","errorCode":"error-invalid-user","errorMessage":"Invalid user to delete","messagePattern":"Invalid user to delete","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/meteor-methods/users/deleteUser.ts","lineNumber":21,"sourceCode":"import { Users } from '@rocket.chat/models';\nimport { check } from 'meteor/check';\nimport { Meteor } from 'meteor/meteor';\n\nimport { hasPermissionAsync } from '../../lib/authorization/hasPermission';\nimport { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';\nimport { 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',","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/users/deleteUser.ts#L3-L39","documentation":"`executeDeleteUser` (the core of the `deleteUser` Meteor method and REST `users.delete`) loads the target with `Users.findOneById(userId)` and throws `error-invalid-user` ('Invalid user to delete') when no user document matches. The check runs after caller permission checks but before any protection logic (app users, last admin), so nothing is deleted and no side effects occur.","triggerScenarios":"Calling `deleteUser(userId, confirmRelinquish?)` with an id that does not exist or was already deleted: double-click on a delete button, stale user list in an admin table, retrying a delete that already succeeded, or a malformed/copied id.","commonSituations":"Two admins deleting the same user concurrently; UI not refreshing after deletion; scripts replaying deletions against a workspace where the user is gone; ids from one environment used against another.","solutions":["Verify the user exists first (`GET /api/v1/users.info?userId=<id>`) before issuing the delete.","In sync/automation scripts, treat `error-invalid-user` on delete as idempotent success.","Refresh the user list after a successful delete and avoid reusing captured ids.","Double-check environment (workspace) when copying ids between instances."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// confirm the target exists before deleting\nconst res = await fetch(`/api/v1/users.info?userId=${encodeURIComponent(userId)}`, { headers: authHeaders });\nif (res.ok) {\n  await deleteUserFn(uid, userId, confirmRelinquish);\n}","typeGuard":"const isExistingUser = (users: { _id: string }[], userId: string): boolean => users.some((u) => u._id === userId);","tryCatchPattern":"try {\n  await Meteor.callAsync('deleteUser', userId, confirmRelinquish);\n} catch (e: any) {\n  if (e?.error === 'error-invalid-user' && e?.reason === 'Invalid user to delete') {\n    return true; // already gone - treat delete as done (idempotent)\n  }\n  throw e;\n}","preventionTips":["Guard delete buttons against double-submit (disable while in flight).","Refresh user lists after deletion; never replay captured ids blindly.","In automation, treat 'user to delete not found' as success."],"tags":["meteor","users","delete","idempotency"],"backgroundTag":"user-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}