{"record":{"id":"89392ec6f846d3c8","repo":"RocketChat/Rocket.Chat","slug":"member-does-not-exist","errorCode":null,"errorMessage":"member-does-not-exist","messagePattern":"member-does-not-exist","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/meteor/server/services/team/service.ts","lineNumber":800,"sourceCode":"\t\t\tthrow new Error('team-does-not-exist');\n\t\t}\n\n\t\tconst membersIds = members.map((m) => m.userId);\n\t\tconst usersToRemove = await Users.findByIds(membersIds, {\n\t\t\tprojection: { _id: 1, username: 1 },\n\t\t}).toArray();\n\t\tconst byUser = await Users.findOneById(uid);\n\n\t\tfor await (const member of members) {\n\t\t\tif (!member.userId) {\n\t\t\t\tthrow new Error('invalid-user');\n\t\t\t}\n\n\t\t\tconst existingMember = await TeamMember.findOneByUserIdAndTeamId(member.userId, team._id);\n\t\t\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(team.roomId, member.userId);\n\n\t\t\tif (!existingMember && !subscription) {\n\t\t\t\tthrow new Error('member-does-not-exist');\n\t\t\t}\n\n\t\t\tif (existingMember) {\n\t\t\t\tif (existingMember.roles?.includes('owner')) {\n\t\t\t\t\tconst totalOwners = await TeamMember.countByTeamIdAndRole(team._id, 'owner');\n\t\t\t\t\tif (totalOwners === 1) {\n\t\t\t\t\t\tthrow new Error('last-owner-can-not-be-removed');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tawait TeamMember.removeById(existingMember._id);\n\t\t\t}\n\n\t\t\tconst removedUser = usersToRemove.find((u) => u._id === (existingMember || member).userId);\n\t\t\tif (removedUser) {\n\t\t\t\tawait removeUserFromRoom(\n\t\t\t\t\tteam.roomId,\n\t\t\t\t\tremovedUser,","sourceCodeStart":782,"sourceCodeEnd":818,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/services/team/service.ts#L782-L818","documentation":"Thrown by TeamService.removeMembers when, for a given member entry, neither a TeamMember document nor a subscription on the team's main room exists (TeamMember.findOneByUserIdAndTeamId and Subscriptions.findOneByRoomIdAndUserId both come back empty). The service checks both collections because a participant may exist only as a room subscriber; finding neither means the user is not on the team. The throw aborts the batch loop, so entries after the failing member are not processed.","triggerScenarios":"Calling Team.removeMembers / POST teams.removeMember with a userId that was already removed (double-submit, two admins removing at once), a user who left via teams.leave, or an id that never belonged to this workspace.","commonSituations":"Stale member list in the admin UI after someone else already removed the user; retry of a timed-out request that actually succeeded; userId copied from a different environment/database.","solutions":["Check membership first with TeamMember.findOneByUserIdAndTeamId(userId, teamId) (and the main-room subscription) and treat absence as success","Re-fetch the member list (GET teams.members) immediately before removing to avoid stale ids","Make the removal flow idempotent: catch member-does-not-exist and return success since the goal state already holds","Verify the userId exists in this workspace via Users.findOneById"],"exampleFix":"// before\nawait Team.removeMembers(uid, teamId, [{ userId }]);\n\n// after\nconst existing = await TeamMember.findOneByUserIdAndTeamId(userId, teamId);\nif (!existing) {\n  // user already not on team — nothing to do\n  return;\n}\nawait Team.removeMembers(uid, teamId, [{ userId }]);","handlingStrategy":"validation","validationCode":"const member = await TeamMember.findOneByUserIdAndTeamId(userId, teamId, { projection: { _id: 1 } });\nconst sub = member ? null : await Subscriptions.findOneByRoomIdAndUserId(team.roomId, userId);\nif (!member && !sub) {\n  // user is not on the team: nothing to remove\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Team.removeMembers(uid, teamId, [{ userId }]);\n} catch (err) {\n  if (err instanceof Error && err.message === 'member-does-not-exist') return; // idempotent no-op\n  throw err;\n}","preventionTips":["Re-fetch the member list immediately before batch removal","Design removal as idempotent — already-removed equals success","Guard against double submits in the UI"],"tags":["teams","member-management","idempotency"],"backgroundTag":"resource-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}