{"record":{"id":"663a3ee3bdddf8ad","repo":"RocketChat/Rocket.Chat","slug":"error-empty-invite-list","errorCode":"error-empty-invite-list","errorMessage":"Cannot invite if no valid users are provided","messagePattern":"Cannot invite if no valid users are provided","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/api/v1/groups.ts","lineNumber":871,"sourceCode":"\n\t\tconst groupRoom = await Rooms.findOneByIdOrName(idOrName);\n\t\tconst { _id: rid, t: type } = groupRoom || {};\n\n\t\tif (!rid || type !== 'p') {\n\t\t\tthrow new Meteor.Error('error-room-not-found', 'The required \"roomId\" or \"roomName\" param provided does not match any group');\n\t\t}\n\n\t\t// Federated rooms invite by raw username: the federated user record is created\n\t\t// lazily inside addUsersToRoomMethod, so we must not require it to exist locally yet.\n\t\tif (groupRoom && isRoomNativeFederated(groupRoom)) {\n\t\t\tconst usernames = await getUsernameListFromParams(this.bodyParams);\n\n\t\t\tawait addUsersToRoomMethod(this.userId, { rid, users: usernames }, this.user);\n\t\t} else {\n\t\t\tconst users = await getUserListFromParams(this.bodyParams);\n\n\t\t\tif (!users.length) {\n\t\t\t\tthrow new Meteor.Error('error-empty-invite-list', 'Cannot invite if no valid users are provided');\n\t\t\t}\n\n\t\t\tawait addUsersToRoomMethod(this.userId, { rid, users: users.map((u) => u.username).filter(isTruthy) }, this.user);\n\t\t}\n\n\t\tconst room = await Rooms.findOneById(rid, { projection: API.v1.defaultFieldsToExclude });\n\n\t\tif (!room) {\n\t\t\tthrow new Meteor.Error('error-room-not-found', 'The required \"roomId\" or \"roomName\" param provided does not match any group');\n\t\t}\n\n\t\treturn API.v1.success({\n\t\t\tgroup: await composeRoomWithLastMessage(room, this.userId),\n\t\t});\n\t},\n);\n\nAPI.v1.post(","sourceCodeStart":853,"sourceCodeEnd":889,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/groups.ts#L853-L889","documentation":"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.","triggerScenarios":"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.","commonSituations":"Inviting by email instead of username. Inviting users from another workspace without federation. Typos in usernames. Inviting deactivated/deleted accounts.","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."],"exampleFix":"// before\nawait POST('/api/v1/groups.invite', { roomId, usernames: ['alice', 'ghost'] }); // 'ghost' missing, 'alice' fine but list still non-empty -> would succeed; single bad invite fails\n\n// after: pre-validate users exist locally\nconst valid = [];\nfor (const u of usernames) {\n  const r = await GET('/api/v1/users.info', { username: u }).catch(() => null);\n  if (r?.user) valid.push(u);\n}\nif (!valid.length) throw new Error('No matching users');\nawait POST('/api/v1/groups.invite', { roomId, usernames: valid });","handlingStrategy":"validation","validationCode":"// Pre-flight: resolve every supplied user to a local account before inviting.\nasync function resolveLocalUsernames(api, usernames) {\n  const out = [];\n  for (const u of usernames) {\n    const r = await api.get('/api/v1/users.info', { username: u }).catch(() => null);\n    if (r?.user?.username) out.push(r.user.username);\n  }\n  return out;\n}\nconst valid = await resolveLocalUsernames(api, usernames);\nif (!valid.length) throw new Error('No matching local users to invite');\nawait api.post('/api/v1/groups.invite', { roomId, usernames: valid });","typeGuard":"function isLocalUserResolved(u) {\n  return u != null && typeof u.username === 'string' && u.username.length > 0;\n}","tryCatchPattern":"try {\n  await api.post('/api/v1/groups.invite', { roomId, usernames });\n} catch (e) {\n  if (isMeteorError(e) && e.reason === 'error-empty-invite-list') {\n    showFormError('None of the supplied users exist in this workspace');\n    return;\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["rest-api","groups","invite","users","validation","federation"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}