RocketChat/Rocket.Chat · warning · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user to delete
What it means
`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.
Source
Thrown at apps/meteor/server/meteor-methods/users/deleteUser.ts:21
import { Users } from '@rocket.chat/models';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import { hasPermissionAsync } from '../../lib/authorization/hasPermission';
import { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';
import { deleteUser } from '../../lib/users/deleteUser';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
deleteUser(userId: IUser['_id'], confirmRelinquish?: boolean): boolean;
}
}
export const executeDeleteUser = async (fromUserId: IUser['_id'], userId: IUser['_id'], confirmRelinquish = false): Promise<boolean> => {
const user = await Users.findOneById(userId);
if (!user) {
throw new Meteor.Error('error-invalid-user', 'Invalid user to delete', {
method: 'deleteUser',
});
}
if (user.type === 'app') {
throw new Meteor.Error('error-cannot-delete-app-user', 'Deleting app user is not allowed', {
method: 'deleteUser',
});
}
const adminCount = await Users.countDocuments({ roles: 'admin' });
const userIsAdmin = user.roles?.indexOf('admin') > -1;
if (adminCount === 1 && userIsAdmin) {
throw new Meteor.Error('error-action-not-allowed', 'Leaving the app without admins is not allowed', {
method: 'deleteUser',
action: 'Remove_last_admin',View on GitHub (pinned to b2c16d5842)
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.
Defensive patterns
Strategy: validation
Validate before calling
// confirm the target exists before deleting
const res = await fetch(`/api/v1/users.info?userId=${encodeURIComponent(userId)}`, { headers: authHeaders });
if (res.ok) {
await deleteUserFn(uid, userId, confirmRelinquish);
} Type guard
const isExistingUser = (users: { _id: string }[], userId: string): boolean => users.some((u) => u._id === userId); Try / catch
try {
await Meteor.callAsync('deleteUser', userId, confirmRelinquish);
} catch (e: any) {
if (e?.error === 'error-invalid-user' && e?.reason === 'Invalid user to delete') {
return true; // already gone - treat delete as done (idempotent)
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Custom_User_Status_Error_Invalid_User_Status
- error-cannot-delete-app-user
- error-action-not-allowed
- error-not-allowed
- error-user-already-in-role
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/49c5f706cd02ff5c.
Report an issue: GitHub.