RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user
What it means
removeRoomOwner loads the target with Users.findOneById(userId) and requires a non-empty username; throws error-invalid-user when the target does not exist or has no username. The userId argument must be the user's _id — passing a username here will always fail this lookup.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/removeRoomOwner.ts:41
check(rid, String);
check(userId, String);
const room = await Rooms.findOneById(rid, { projection: { t: 1, federated: 1, federation: 1 } });
if (!room) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'removeRoomOwner',
});
}
if (!(await hasPermissionAsync(fromUserId, 'set-owner', rid)) && !isRoomFederated(room)) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'removeRoomOwner',
});
}
const user = await Users.findOneById(userId);
if (!user?.username) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'removeRoomOwner',
});
}
const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);
if (!subscription) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'removeRoomOwner',
});
}
if (Array.isArray(subscription.roles) === false || subscription.roles?.includes('owner') === false) {
throw new Meteor.Error('error-user-not-owner', 'User is not an owner', {
method: 'removeRoomOwner',
});
}
View on GitHub (pinned to b2c16d5842)
Solutions
- Resolve the target's _id (Users.findOneByUsername, or GET /api/v1/users.info?username=) before calling
- Validate that the user exists and has a username before offering owner-removal actions
- Drop stale targets from pickers when lookup fails
Example fix
// before
await Meteor.callAsync('removeRoomOwner', rid, targetUsername);
// after
const user = Users.findOne({ username: targetUsername });
if (!user?._id) throw new Error('target missing');
await Meteor.callAsync('removeRoomOwner', rid, user._id); Defensive patterns
Strategy: validation
Validate before calling
const target = Users.findOne({ _id: userId });
if (!target?.username) {
// target missing: skip call and refresh pickers
} Type guard
const isRemovableUser = (u: { _id?: string; username?: string } | null | undefined): u is { _id: string; username: string } =>
Boolean(u?._id && u?.username); Try / catch
try {
await Meteor.callAsync('removeRoomOwner', rid, userId);
} catch (err) {
if (err instanceof Meteor.Error && err.error === 'error-invalid-user') {
// target vanished: refresh member data
}
} Prevention
- Pass the target's _id, not username
- Resolve users through a fresh lookup
- Purge stale entries from selection UI
When it happens
Trigger: Passing the target's username rather than _id as the second argument; target deleted before the call landed; user record without a username.
Common situations: Member-management UIs keyed by username; target account removed while an admin had the role dialog open.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/d8789ebc64fd5197.
Report an issue: GitHub.