RocketChat/Rocket.Chat · warning · Meteor.Error
error-empty-invite-list
error-empty-invite-list
Error message
Cannot invite if no valid users are provided
What it means
Thrown by groups.invite (groups.ts:868-872) in the non-federated branch. getUserListFromParams resolves userId/username/user/userIds/usernames to local user documents; if the resulting list is empty, none of the supplied identifiers matched a local user. (Note: getUserListFromParams itself throws error-users-params-not-provided when no user param is sent at all, so reaching this empty-list check means at least one identifier was supplied but none resolved.) Federated rooms take a different branch (getUsernameListFromParams) and never reach this throw.
Source
Thrown at apps/meteor/server/api/v1/groups.ts:871
const groupRoom = await Rooms.findOneByIdOrName(idOrName);
const { _id: rid, t: type } = groupRoom || {};
if (!rid || type !== 'p') {
throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "roomName" param provided does not match any group');
}
// Federated rooms invite by raw username: the federated user record is created
// lazily inside addUsersToRoomMethod, so we must not require it to exist locally yet.
if (groupRoom && isRoomNativeFederated(groupRoom)) {
const usernames = await getUsernameListFromParams(this.bodyParams);
await addUsersToRoomMethod(this.userId, { rid, users: usernames }, this.user);
} else {
const users = await getUserListFromParams(this.bodyParams);
if (!users.length) {
throw new Meteor.Error('error-empty-invite-list', 'Cannot invite if no valid users are provided');
}
await addUsersToRoomMethod(this.userId, { rid, users: users.map((u) => u.username).filter(isTruthy) }, this.user);
}
const room = await Rooms.findOneById(rid, { projection: API.v1.defaultFieldsToExclude });
if (!room) {
throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "roomName" param provided does not match any group');
}
return API.v1.success({
group: await composeRoomWithLastMessage(room, this.userId),
});
},
);
API.v1.post(View on GitHub (pinned to f9d3ec372b)
Solutions
- Resolve each user identifier to a local user first (e.g. via users.info) and drop unknowns before calling invite.
- Confirm you are inviting existing local users; for cross-workspace invites, enable federation and use the federated username format (user@server).
- Supply userIds/usernames exactly as they appear in the workspace directory.
- If the group is meant to be federated, verify isRoomNativeFederated is true so the invite takes the username-passthrough branch.
Example fix
// before
await POST('/api/v1/groups.invite', { roomId, usernames: ['alice', 'ghost'] }); // 'ghost' missing, 'alice' fine but list still non-empty -> would succeed; single bad invite fails
// after: pre-validate users exist locally
const valid = [];
for (const u of usernames) {
const r = await GET('/api/v1/users.info', { username: u }).catch(() => null);
if (r?.user) valid.push(u);
}
if (!valid.length) throw new Error('No matching users');
await POST('/api/v1/groups.invite', { roomId, usernames: valid }); Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: resolve every supplied user to a local account before inviting.
async function resolveLocalUsernames(api, usernames) {
const out = [];
for (const u of usernames) {
const r = await api.get('/api/v1/users.info', { username: u }).catch(() => null);
if (r?.user?.username) out.push(r.user.username);
}
return out;
}
const valid = await resolveLocalUsernames(api, usernames);
if (!valid.length) throw new Error('No matching local users to invite');
await api.post('/api/v1/groups.invite', { roomId, usernames: valid }); Type guard
function isLocalUserResolved(u) {
return u != null && typeof u.username === 'string' && u.username.length > 0;
} Try / catch
try {
await api.post('/api/v1/groups.invite', { roomId, usernames });
} catch (e) {
if (isMeteorError(e) && e.reason === 'error-empty-invite-list') {
showFormError('None of the supplied users exist in this workspace');
return;
}
throw e;
} Prevention
- Invite by exact local usernames, not emails or display names.
- For cross-workspace invites, enable federation and use user@server form on a federated room.
- Validate the user list against the workspace directory before submitting.
- Distinguish the federated (username-passthrough) branch from the local branch when debugging.
When it happens
Trigger: POST groups.invite on a native (non-federated) private group where every supplied userId/username/user/userIds/usernames refers to a non-existent, deleted, or misspelled user. Also when usernames are correct but federation is disabled so they have no local record.
Common situations: Inviting by email instead of username. Inviting users from another workspace without federation. Typos in usernames. Inviting deactivated/deleted accounts.
Related errors
- error-room-param-not-provided
- error-room-not-found
- Creating normal users is currently not supported
- User not provided
- Invalid user id
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/663a3ee3bdddf8ad.
Report an issue: GitHub.