RocketChat/Rocket.Chat · warning · Error
member-does-not-exist
Error message
member-does-not-exist
What it means
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.
Source
Thrown at apps/meteor/server/services/team/service.ts:800
throw new Error('team-does-not-exist');
}
const membersIds = members.map((m) => m.userId);
const usersToRemove = await Users.findByIds(membersIds, {
projection: { _id: 1, username: 1 },
}).toArray();
const byUser = await Users.findOneById(uid);
for await (const member of members) {
if (!member.userId) {
throw new Error('invalid-user');
}
const existingMember = await TeamMember.findOneByUserIdAndTeamId(member.userId, team._id);
const subscription = await Subscriptions.findOneByRoomIdAndUserId(team.roomId, member.userId);
if (!existingMember && !subscription) {
throw new Error('member-does-not-exist');
}
if (existingMember) {
if (existingMember.roles?.includes('owner')) {
const totalOwners = await TeamMember.countByTeamIdAndRole(team._id, 'owner');
if (totalOwners === 1) {
throw new Error('last-owner-can-not-be-removed');
}
}
await TeamMember.removeById(existingMember._id);
}
const removedUser = usersToRemove.find((u) => u._id === (existingMember || member).userId);
if (removedUser) {
await removeUserFromRoom(
team.roomId,
removedUser,View on GitHub (pinned to b2c16d5842)
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
Example fix
// before
await Team.removeMembers(uid, teamId, [{ userId }]);
// after
const existing = await TeamMember.findOneByUserIdAndTeamId(userId, teamId);
if (!existing) {
// user already not on team — nothing to do
return;
}
await Team.removeMembers(uid, teamId, [{ userId }]); Defensive patterns
Strategy: validation
Validate before calling
const member = await TeamMember.findOneByUserIdAndTeamId(userId, teamId, { projection: { _id: 1 } });
const sub = member ? null : await Subscriptions.findOneByRoomIdAndUserId(team.roomId, userId);
if (!member && !sub) {
// user is not on the team: nothing to remove
return;
} Try / catch
try {
await Team.removeMembers(uid, teamId, [{ userId }]);
} catch (err) {
if (err instanceof Error && err.message === 'member-does-not-exist') return; // idempotent no-op
throw err;
} Prevention
- Re-fetch the member list immediately before batch removal
- Design removal as idempotent — already-removed equals success
- Guard against double submits in the UI
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- error-room-is-already-on-hold
- error-room-not-on-hold
- error-token-does-not-exists
- error-invalid-user
- Param ${params.teams.key} must be an array
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/89392ec6f846d3c8.
Report an issue: GitHub.