RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
Invalid user
What it means
Thrown by the getRoomById Meteor method when the DDP connection has no authenticated user (Meteor.userId() is null). Note the error details carry method: 'getRoomNameById' - a copy-paste artifact in the source - so do not rely on details.method to identify which call failed; match on the error code 'error-invalid-user' instead.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/getRoomById.ts:22
import { check } from 'meteor/check';
import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
import { Meteor } from 'meteor/meteor';
import { canAccessRoomAsync } from '../../lib/authorization';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
getRoomById(rid: IRoom['_id']): IRoom;
}
}
Meteor.methods<ServerMethods>({
async getRoomById(rid) {
check(rid, String);
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'getRoomNameById',
});
}
const room = await Rooms.findOneById(rid);
if (room == null) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'getRoomNameById',
});
}
if (!(await canAccessRoomAsync(room, (await Meteor.userAsync()) as IUser))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'getRoomById',
});
}
return room;
},
});View on GitHub (pinned to b2c16d5842)
Solutions
- Guard the call site: only invoke getRoomById when Meteor.userId() is truthy
- Re-authenticate if the token expired (password login or SSO) to establish a new session
- Audit reactive autoruns that call room methods and make them conditional on Meteor.userId()
- For machine-to-machine use, call the REST equivalent GET /api/v1/rooms.info with an auth token instead of an anonymous DDP call
Example fix
// before
const room = await Meteor.callAsync('getRoomById', rid);
// after
if (!Meteor.userId()) throw new Error('login required');
const room = await Meteor.callAsync('getRoomById', rid); Defensive patterns
Strategy: validation
Validate before calling
// client: gate the call on an established session
if (!Meteor.userId()) {
throw new Error('login required');
}
const room = await Meteor.callAsync('getRoomById', rid); Try / catch
try {
const room = await Meteor.callAsync('getRoomById', rid);
} catch (e) {
// details.method is 'getRoomNameById' here (source bug) - match on the code only
if (e instanceof Meteor.Error && e.error === 'error-invalid-user') {
showLoginScreen();
}
} Prevention
- Do not branch on err.details.method for this method - the source labels it 'getRoomNameById'
- Make reactive room lookups conditional on Meteor.userId() in autoruns
- Use REST /v1/rooms.info with token auth for integrations instead of anonymous DDP calls
When it happens
Trigger: Calling Meteor.call('getRoomById', rid) from an anonymous connection: the client never logged in, logged out, or its resume token expired and was purged, so Meteor.userId() returns null before check(rid, String) even matters.
Common situations: Client calls a room method before Accounts login completes; session expired after long idle; logout race where a reactive autorun fires the call after logout; server-side integration code invoking the method without a userId bound to the connection.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/393c0e3c15db32bb.
Report an issue: GitHub.