{"record":{"id":"5309f43504f7e93f","repo":"RocketChat/Rocket.Chat","slug":"error-user-not-in-room-5309f4","errorCode":"error-user-not-in-room","errorMessage":"User is not in this room","messagePattern":"User is not in this room","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/removeUserFromRoom.ts","lineNumber":60,"sourceCode":"\n\tconst fromUser = await Users.findOneById(fromId);\n\tif (!fromUser) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'removeUserFromRoom',\n\t\t});\n\t}\n\n\t// did this way so a ctrl-f would find the permission being used\n\tconst kickAnyUserPermission = room.t === 'c' ? 'kick-user-from-any-c-room' : 'kick-user-from-any-p-room';\n\n\tconst canKickAnyUser = await hasPermissionAsync(fromId, kickAnyUserPermission);\n\tif (!canKickAnyUser && !(await canAccessRoomAsync(room, fromUser))) {\n\t\tthrow new Meteor.Error('error-room-not-found', 'The required \"roomId\" or \"roomName\" param provided does not match any group');\n\t}\n\n\tconst removedUser = await Users.findOneByUsernameIgnoringCase(data.username);\n\tif (!removedUser) {\n\t\tthrow new Meteor.Error('error-user-not-in-room', 'User is not in this room', {\n\t\t\tmethod: 'removeUserFromRoom',\n\t\t});\n\t}\n\n\tawait Room.beforeUserRemoved(room);\n\n\tif (!canKickAnyUser) {\n\t\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, removedUser._id, {\n\t\t\tprojection: { _id: 1 },\n\t\t});\n\t\tif (!subscription) {\n\t\t\tthrow new Meteor.Error('error-user-not-in-room', 'User is not in this room', {\n\t\t\t\tmethod: 'removeUserFromRoom',\n\t\t\t});\n\t\t}\n\t}\n\n\tif (await hasRoleAsync(removedUser._id, 'owner', room._id)) {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/removeUserFromRoom.ts#L42-L78","documentation":"Thrown by the 'removeUserFromRoom' Meteor (DDP) method when the target username supplied in data.username does not match any user document at all (Users.findOneByUsernameIgnoringCase returns null). Despite the code 'error-user-not-in-room' and message 'User is not in this room', this specific throw means the user does not exist in the workspace (the lookup is case-insensitive). A different throw at line 72 is the one that actually means 'user exists but has no subscription'. The equivalent REST endpoints are /v1/channels.kick and /v1/groups.kick.","triggerScenarios":"Calling Meteor.call('removeUserFromRoom', { rid, username }) or removeUserFromRoomMethod(fromId, data) where username is misspelled, belongs to a deleted user, or the account was renamed. Also triggered when data.username is an empty string or contains whitespace, since the exact (case-insensitive) string is used for the lookup.","commonSituations":"Stale client UI still showing a removed/deleted member after the user was deleted server-side; bots or integrations kicking by an outdated username after a rename; copy/paste of usernames with trailing spaces; passing a user _id or email instead of the username.","solutions":["Verify the username exists before calling (e.g. GET /api/v1/users.info?username=..., or check the room member list) and send the exact, current username.","Trim/normalize the username string and confirm you are not accidentally passing userId or an email address.","Handle this error as a non-retryable no-op in idempotent automation: the user cannot be in the room if they do not exist.","If the username was recently changed, fetch the fresh username from the room's subscription/member data instead of caching it."],"exampleFix":"// before\nMeteor.call('removeUserFromRoom', { rid, username: 'john.doe ' }); // typo/whitespace -> error-user-not-in-room\n\n// after\nconst username = rawUsername.trim();\nconst info = await fetch(`/api/v1/users.info?username=${encodeURIComponent(username)}`); // 400 'user-not-found' if missing\nif (!info.ok) throw new Error(`No such user: ${username}`);\nMeteor.call('removeUserFromRoom', { rid, username: info.user.username });","handlingStrategy":"validation","validationCode":"// Resolve and verify the username before kicking\nconst normalized = String(username).trim();\nconst res = await fetch(`/api/v1/users.info?username=${encodeURIComponent(normalized)}`, { headers: authHeaders });\nif (!res.ok) {\n  throw new Error(`Cannot remove: no user '${normalized}' exists in this workspace`);\n}\nconst { user } = await res.json(); // use user.username (canonical case)\nawait kick(rid, user.username);","typeGuard":"const isValidUsername = (u: unknown): u is string =>\n  typeof u === 'string' && u.trim().length > 0 && !u.includes(' ') && !/.+@.+\\..+/.test(u) && u !== 'me';","tryCatchPattern":"try {\n  await Meteor.callAsync('removeUserFromRoom', { rid, username });\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-user-not-in-room') {\n    // Distinguish: 1540 means the user does not exist at all\n    console.warn(`User '${username}' not found; nothing to remove`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Always pass the canonical username from a fresh user lookup, never a cached or hand-typed value.","Trim whitespace and reject empty strings before invoking the method.","Never substitute userId or email where the API expects username.","Treat 'user does not exist' as a terminal condition — do not retry."],"tags":["rocket-chat","meteor-method","room-management","user-lookup","kick-user"],"backgroundTag":"user-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}