RocketChat/Rocket.Chat · error · Meteor.Error
error-user-not-found
error-user-not-found
Error message
User not found
What it means
Thrown inside the per-user loop of addUsersToRoomMethod() (apps/meteor/server/meteor-methods/rooms/addUsersToRoom.ts:94) when Users.findOneByUsernameIgnoringCase(sanitizedUsername) returns null — no user matches the given username (after sanitizeUsername strips a leading '@' or keeps federated user@domain:server forms). Because the loop runs inside Promise.all over all requested usernames, one unknown username rejects the entire invitation batch.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/addUsersToRoom.ts:94
});
}
// Missing the users to be added
if (!Array.isArray(data.users)) {
throw new Meteor.Error('error-invalid-arguments', 'Invalid arguments', {
method: 'addUsersToRoom',
});
}
await beforeAddUsersToRoom.run({ usernames: data.users, inviter: user }, room);
await Promise.all(
data.users.map(async (username) => {
const sanitizedUsername = sanitizeUsername(username);
const newUser = await Users.findOneByUsernameIgnoringCase(sanitizedUsername);
if (!newUser) {
throw new Meteor.Error('error-user-not-found', 'User not found', {
method: 'addUsersToRoom',
});
}
const subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, newUser._id);
if (subscription && isBannedSubscription(subscription)) {
throw new Meteor.Error('error-user-is-banned', 'User is banned from this room', {
method: 'addUsersToRoom',
});
}
if (!subscription) {
return addUserToRoom(data.rid, newUser, user);
}
if (!newUser.username) {
return;
}
void api.broadcast('notify.ephemeralMessage', userId, data.rid, {
msg: i18n.t('Username_is_already_in_here', {View on GitHub (pinned to b2c16d5842)
Solutions
- Resolve usernames ahead of time and drop unknown ones (or report them) so one bad entry does not abort the batch: const found = await Users.findOneByUsernameIgnoringCase(name).
- Send the exact username (not display name/email); strip leading '@' — the sanitizer handles '@name' but not every variation.
- If users come from an external source, wait for/verify provisioning (SCIM/LDAP import) before inviting.
- For federated targets, verify the full user@domain:server form and that federation is enabled, otherwise invite the local account name.
Example fix
// before
await addUsersToRoomMethod(uid, { rid, users: ['alice', 'bob-typo'] }); // whole batch fails
// after
const users = (
await Promise.all(
raw.map(async (name) => {
const u = await Users.findOneByUsernameIgnoringCase(sanitizeUsername(name), { projection: { username: 1 } });
return u?.username;
}),
)
).filter(Boolean) as string[];
await addUsersToRoomMethod(uid, { rid, users }); Defensive patterns
Strategy: validation
Validate before calling
const found = await Users.findOneByUsernameIgnoringCase(sanitizeUsername(name), { projection: { username: 1 } });
if (!found?.username) continue; // collect unknown names and report instead of aborting the batch Type guard
const isKnownUsername = async (name: string): Promise<boolean> =>
Boolean(await Users.findOneByUsernameIgnoringCase(sanitizeUsername(name), { projection: { _id: 1 } })); Try / catch
try {
await addUsersToRoomMethod(uid, { rid, users });
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-user-not-found') {
// resolve each username first; invite the subset that exists and report the rest
}
} Prevention
- Pre-resolve usernames before bulk invites so one bad entry cannot reject the batch.
- Use exact usernames (not display names/emails); strip leading '@'.
- For external directories, sync/verify provisioning before inviting.
When it happens
Trigger: Inviting by a username with a typo; the account was deleted or renamed before the invite; inviting by display name or email instead of username; federated username with a malformed user@domain:server shape so it is looked up verbatim and misses; trailing whitespace or a masked/mentioned format the sanitizer does not normalize.
Common situations: Bots inviting from an external directory that is out of sync with Rocket.Chat users; user renames breaking stored lists; provisioning lag where the invite fires before the user import finished; mixing up username and name fields in spreadsheets.
Related errors
- error-invalid-username
- error-blocked-username
- error-input-is-not-a-valid-field
- error-invalid-user
- error-invalid-user
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/5127e3895c4cc616.
Report an issue: GitHub.