{"record":{"id":"9a78c40323d0026d","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-9a78c4","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/getRoomJoinCode.ts","lineNumber":23,"sourceCode":"import { Meteor } from 'meteor/meteor';\n\nimport { hasPermissionAsync } from '../../lib/authorization/hasPermission';\n\ndeclare module '@rocket.chat/ddp-client' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface ServerMethods {\n\t\tgetRoomJoinCode(rid: string): string | false;\n\t}\n}\n/* @deprecated */\nMeteor.methods<ServerMethods>({\n\tasync getRoomJoinCode(rid) {\n\t\tcheck(rid, String);\n\n\t\tconst userId = Meteor.userId();\n\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getJoinCode' });\n\t\t}\n\n\t\tif (!(await hasPermissionAsync(userId, 'view-join-code'))) {\n\t\t\tthrow new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'getJoinCode' });\n\t\t}\n\n\t\tconst room = await Rooms.findById(rid);\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\treturn Boolean(room) && (isRoomWithJoinCode(room!) ? room.joinCode : false);\n\t},\n});\n","sourceCodeStart":5,"sourceCodeEnd":36,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/getRoomJoinCode.ts#L5-L36","documentation":"Thrown by the deprecated getRoomJoinCode Meteor method when the connection has no authenticated user. The check is Meteor.userId() based, so it fires for never-logged-in, logged-out, and expired-token connections alike; the returned join code is only ever exposed to identified users.","triggerScenarios":"Meteor.call('getRoomJoinCode', rid) from an anonymous DDP connection, e.g. pre-login UI code trying to display a join code, or a logged-out tab still running reactive logic.","commonSituations":"Onboarding screens that render before Accounts login finishes; sessions invalidated by server restart or token purge; test harnesses calling the method without a user.","solutions":["Guard the call with Meteor.userId() and defer it until login completes","Re-login if the resume token expired","Prefer room.join with the join code via the REST API (/v1/rooms.join) instead of exposing join codes through DDP"],"exampleFix":"// before\nconst code = await Meteor.callAsync('getRoomJoinCode', rid);\n\n// after\nif (!Meteor.userId()) throw new Error('login required');\nconst code = await Meteor.callAsync('getRoomJoinCode', rid);","handlingStrategy":"validation","validationCode":"if (!Meteor.userId()) {\n  throw new Error('login required');\n}\nconst code = await Meteor.callAsync('getRoomJoinCode', rid);","typeGuard":"// the method returns string | false\nconst isJoinCode = (v: string | false): v is string => typeof v === 'string';\nconst code = await Meteor.callAsync('getRoomJoinCode', rid);\nif (isJoinCode(code)) displayCode(code);","tryCatchPattern":"try {\n  const code = await Meteor.callAsync('getRoomJoinCode', rid);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === 'error-invalid-user') {\n    showLoginScreen();\n  } else if (e instanceof Meteor.Error && e.error === 'error-not-authorized') {\n    hideJoinCodeUI(); // handled at 1488\n  }\n}","preventionTips":["Method is deprecated - prefer /v1/rooms.join with joinCode over exposing codes via DDP","Only render join-code UI for authenticated admin-capable users","Treat join codes as secrets: do not log or embed them in links"],"tags":["meteor","ddp","authentication","rooms","join-code","deprecated"],"backgroundTag":"unauthenticated-request","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}