{"record":{"id":"f88b51110add682a","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-f88b51","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/users/getUsersOfRoom.ts","lineNumber":37,"sourceCode":"\t\t\tfilter?: string,\n\t\t): {\n\t\t\ttotal: number;\n\t\t\trecords: IUser[];\n\t\t};\n\t}\n}\n\nMeteor.methods<ServerMethods>({\n\tasync getUsersOfRoom(rid, showAll, { limit, skip } = {}, filter) {\n\t\tif (!rid) {\n\t\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getUsersOfRoom' });\n\t\t}\n\n\t\tcheck(rid, String);\n\n\t\tconst userId = Meteor.userId();\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getUsersOfRoom' });\n\t\t}\n\n\t\tconst room = await Rooms.findOneById(rid, { projection: { ...roomAccessAttributes, broadcast: 1 } });\n\t\tif (!room) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getUsersOfRoom' });\n\t\t}\n\n\t\tif (!(await canAccessRoomAsync(room, { _id: userId }))) {\n\t\t\tthrow new Meteor.Error('not-authorized', 'Not Authorized', { method: 'getUsersOfRoom' });\n\t\t}\n\n\t\tif (room.broadcast && !(await hasPermissionAsync(userId, 'view-broadcast-member-list', rid))) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getUsersOfRoom' });\n\t\t}\n\n\t\t// TODO this is currently counting deactivated users\n\t\tconst total = await Subscriptions.countByRoomIdWhenUsernameExists(rid);\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/users/getUsersOfRoom.ts#L19-L55","documentation":"The getUsersOfRoom method requires a logged-in caller: Meteor.userId() returned null, so it throws error-invalid-user before any room lookup. Membership listing is never served to anonymous connections, even for public rooms.","triggerScenarios":"Meteor.callAsync('getUsersOfRoom', rid, ...) on a connection without a valid login token — guest session, after logout, or expired resume token.","commonSituations":"Member lists rendered on public/preview pages; token expiry on long-lived tabs; calls racing a logout or server restart that cleared tokens.","solutions":["Guard the call with Meteor.userId() and skip member listing for anonymous views","Re-authenticate and retry once on this error","Ensure the call uses the same DDP connection the user logged in on"],"exampleFix":"// before\nMeteor.callAsync('getUsersOfRoom', rid, showAll, {}, filter);\n\n// after\nif (!Meteor.userId()) {\n\tthrow new Error('login required');\n}\nawait Meteor.callAsync('getUsersOfRoom', rid, showAll, {}, filter);","handlingStrategy":"validation","validationCode":"if (!Meteor.userId()) {\n\treturn; // no session — skip member fetch\n}\nawait Meteor.callAsync('getUsersOfRoom', rid, showAll, { limit, skip }, filter);","typeGuard":null,"tryCatchPattern":"try {\n\tawait Meteor.callAsync('getUsersOfRoom', rid, showAll, {}, filter);\n} catch (err) {\n\tif ((err as { error?: string }).error === 'error-invalid-user') {\n\t\t// re-login and retry once\n\t}\n}","preventionTips":["Require a session before mounting member-list UI","Handle expired tokens centrally instead of per component","Keep the DDP connection used for login and for method calls the same"],"tags":["meteor","ddp","authentication","rooms","members"],"backgroundTag":"user-not-authenticated","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}