{"record":{"id":"6476713d32a07f8d","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-647671","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/removeRoomModerator.ts","lineNumber":43,"sourceCode":"\tcheck(userId, String);\n\n\tconst room = await Rooms.findOneById(rid, { projection: { t: 1, federated: 1, federation: 1 } });\n\tif (!room) {\n\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\tmethod: 'removeRoomModerator',\n\t\t});\n\t}\n\n\tif (!(await hasPermissionAsync(fromUserId, 'set-moderator', rid)) && !isRoomFederated(room)) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'removeRoomModerator',\n\t\t});\n\t}\n\n\tconst user = await Users.findOneById(userId);\n\n\tif (!user?.username) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'removeRoomModerator',\n\t\t});\n\t}\n\n\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);\n\n\tif (!subscription) {\n\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\tmethod: 'removeRoomModerator',\n\t\t});\n\t}\n\n\tif (subscription.roles && (!Array.isArray(subscription.roles) || !subscription.roles.includes('moderator'))) {\n\t\tthrow new Meteor.Error('error-user-not-moderator', 'User is not a moderator', {\n\t\t\tmethod: 'removeRoomModerator',\n\t\t});\n\t}\n","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/removeRoomModerator.ts#L25-L61","documentation":"After the room and permission gates, removeRoomModerator loads the target via Users.findOneById(userId) and requires a non-empty username. Throws error-invalid-user when the target user document does not exist or has no username (deleted user or incomplete record). The second argument is the user's _id, not their username.","triggerScenarios":"Passing the target's username instead of _id; the target user was deleted before the call landed; a user record created without a username (registration never finished).","commonSituations":"Custom member-management UI storing usernames where IDs are expected; target deleted by an admin while the role dialog was open; imported users missing usernames.","solutions":["Resolve the target's _id first (Users.findOneByUsername on the client, or GET /api/v1/users.info) and pass that","Confirm the target still exists and has a username before showing role actions","Remove stale users from pickers when the users.info lookup fails"],"exampleFix":"// before\nawait Meteor.callAsync('removeRoomModerator', rid, targetUsername);\n\n// after\nconst user = Users.findOne({ username: targetUsername });\nif (!user?._id) throw new Error('target missing');\nawait Meteor.callAsync('removeRoomModerator', rid, user._id);","handlingStrategy":"validation","validationCode":"const target = Users.findOne({ _id: userId });\nif (!target?.username) {\n  // target missing or incomplete; do not call\n}","typeGuard":"const isRemovableUser = (u: { _id?: string; username?: string } | null | undefined): u is { _id: string; username: string } =>\n  Boolean(u?._id && u?.username);","tryCatchPattern":"try {\n  await Meteor.callAsync('removeRoomModerator', rid, userId);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-invalid-user') {\n    // target user not found: drop them from pickers, refresh members\n  }\n}","preventionTips":["Resolve targets by _id from a fresh lookup","Pass user _id, never username, as the second argument","Drop users from selection UI when lookup fails"],"tags":["users","meteor-methods","validation"],"backgroundTag":"user-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}