RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user
What it means
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.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/getRoomJoinCode.ts:23
import { Meteor } from 'meteor/meteor';
import { hasPermissionAsync } from '../../lib/authorization/hasPermission';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
getRoomJoinCode(rid: string): string | false;
}
}
/* @deprecated */
Meteor.methods<ServerMethods>({
async getRoomJoinCode(rid) {
check(rid, String);
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getJoinCode' });
}
if (!(await hasPermissionAsync(userId, 'view-join-code'))) {
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'getJoinCode' });
}
const room = await Rooms.findById(rid);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return Boolean(room) && (isRoomWithJoinCode(room!) ? room.joinCode : false);
},
});
View on GitHub (pinned to b2c16d5842)
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
Example fix
// before
const code = await Meteor.callAsync('getRoomJoinCode', rid);
// after
if (!Meteor.userId()) throw new Error('login required');
const code = await Meteor.callAsync('getRoomJoinCode', rid); Defensive patterns
Strategy: validation
Validate before calling
if (!Meteor.userId()) {
throw new Error('login required');
}
const code = await Meteor.callAsync('getRoomJoinCode', rid); Type guard
// the method returns string | false
const isJoinCode = (v: string | false): v is string => typeof v === 'string';
const code = await Meteor.callAsync('getRoomJoinCode', rid);
if (isJoinCode(code)) displayCode(code); Try / catch
try {
const code = await Meteor.callAsync('getRoomJoinCode', rid);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-invalid-user') {
showLoginScreen();
} else if (e instanceof Meteor.Error && e.error === 'error-not-authorized') {
hideJoinCodeUI(); // handled at 1488
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Onboarding screens that render before Accounts login finishes; sessions invalidated by server restart or token purge; test harnesses calling the method without a user.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/9a78c40323d0026d.
Report an issue: GitHub.