RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-user

error-invalid-user

Error message

Invalid user

What it means

executeGetRoomRoles (the shared implementation behind the getRoomRoles DDP method) rejects the call when no user context was supplied (fromUser is falsy) and the workspace setting Accounts_AllowAnonymousRead is false. Room roles are only served to identified users unless the workspace explicitly enables anonymous read access.

Source

Thrown at apps/meteor/server/meteor-methods/rooms/getRoomRoles.ts:22

import { Meteor } from 'meteor/meteor';

import { canAccessRoomAsync } from '../../lib/authorization';
import type { RoomRoles } from '../../lib/roles/getRoomRoles';
import { getRoomRoles } from '../../lib/roles/getRoomRoles';
import { settings } from '../../settings';

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		getRoomRoles(rid: IRoom['_id']): RoomRoles[];
	}
}

export const executeGetRoomRoles = async (rid: IRoom['_id'], fromUser?: IUser | null) => {
	check(rid, String);

	if (!fromUser && settings.get('Accounts_AllowAnonymousRead') === false) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getRoomRoles' });
	}

	const room = await Rooms.findOneById(rid);
	if (!room) {
		throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getRoomRoles' });
	}

	if (fromUser && !(await canAccessRoomAsync(room, fromUser))) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getRoomRoles' });
	}

	return getRoomRoles(rid);
};

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pass the logged-in user: call the DDP method only when Meteor.userId() exists, or supply fromUser = await Meteor.userAsync() when invoking executeGetRoomRoles directly
  2. Enable Administration -> General -> Accounts -> Accounts_AllowAnonymousRead if anonymous room reads are intended
  3. Redirect anonymous users to a login flow before loading room roles

Example fix

// before - direct call without user context
const roles = await executeGetRoomRoles(rid);

// after - pass the requesting user
const user = await Meteor.userAsync();
const roles = await executeGetRoomRoles(rid, user);
Defensive patterns

Strategy: validation

Validate before calling

// pass the requesting user whenever one exists
const user = await Meteor.userAsync();
if (!user && settings.get?.('Accounts_AllowAnonymousRead') === false) {
  throw new Error('login required');
}
const roles = await executeGetRoomRoles(rid, user ?? undefined);

Try / catch

try {
  const roles = await Meteor.callAsync('getRoomRoles', rid);
} catch (e) {
  if (e instanceof Meteor.Error && e.error === 'error-invalid-user') {
    // either anonymous on a closed workspace or (1494) access denied - recheck auth first
    if (!Meteor.userId()) showLoginScreen();
  }
}

Prevention

When it happens

Trigger: Calling Meteor.call('getRoomRoles', rid) while logged out on a default workspace; invoking executeGetRoomRoles(rid) programmatically without passing the requesting user; disabling Accounts_AllowAnonymousRead while a public site still renders room content anonymously.

Common situations: Embedded/anonymous viewers of a workspace after the admin toggles Accounts_AllowAnonymousRead off; server code importing executeGetRoomRoles directly and forgetting the fromUser argument; guest access features tested without login.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/38e1679152a2ad69. Report an issue: GitHub.