RocketChat/Rocket.Chat · error · Meteor.Error

invalid-user

invalid-user

Error message

Invalid user

What it means

Thrown by saveRoomEncrypted when isRegisterUser(user) is false (saveRoomEncrypted.ts:19). isRegisterUser (packages/core-typings/src/IUser.ts:255) requires user.username !== undefined && user.name !== undefined, so partial user objects and nameless app/bot users fail. Code 'invalid-user', details { function: 'RocketChat.saveRoomEncrypted' }.

Source

Thrown at apps/meteor/server/lib/rooms/settings/saveRoomEncrypted.ts:19

import { Message } from '@rocket.chat/core-services';
import type { IUser } from '@rocket.chat/core-typings';
import { isRegisterUser } from '@rocket.chat/core-typings';
import { Rooms, Subscriptions } from '@rocket.chat/models';
import { Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import type { UpdateResult } from 'mongodb';

import { notifyOnSubscriptionChangedByRoomId } from '../../notifyListener';

export const saveRoomEncrypted = async function (rid: string, encrypted: boolean, user: IUser, sendMessage = true): Promise<UpdateResult> {
	if (!Match.test(rid, String)) {
		throw new Meteor.Error('invalid-room', 'Invalid room', {
			function: 'RocketChat.saveRoomEncrypted',
		});
	}

	if (!isRegisterUser(user)) {
		throw new Meteor.Error('invalid-user', 'Invalid user', {
			function: 'RocketChat.saveRoomEncrypted',
		});
	}

	const update = await Rooms.saveEncryptedById(rid, encrypted);
	if (update && sendMessage) {
		const type = encrypted ? 'room_e2e_enabled' : 'room_e2e_disabled';

		await Message.saveSystemMessage(type, rid, user.username, user);
	}

	if (encrypted) {
		const { modifiedCount } = await Subscriptions.disableAutoTranslateByRoomId(rid);
		if (modifiedCount) {
			void notifyOnSubscriptionChangedByRoomId(rid);
		}
	}
	return update;

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Load the full user: const user = await Users.findOneById(userId) and pass that
  2. Ensure the user profile has a non-empty name and a username
  3. Pre-check with isRegisterUser(user) from '@rocket.chat/core-typings'
  4. Match on code 'invalid-user' (no error- prefix) when catching

Example fix

// before
await saveRoomEncrypted(rid, encrypted, { _id: uid } as IUser);

// after
const user = await Users.findOneById(uid);
if (!user || !isRegisterUser(user)) {
	throw new Meteor.Error('invalid-user', 'Invalid user', { function: 'RocketChat.saveRoomEncrypted' });
}
await saveRoomEncrypted(rid, encrypted, user);
Defensive patterns

Strategy: type-guard

Validate before calling

const user = await Users.findOneById(userId);
if (!user || !isRegisterUser(user)) {
	throw new Meteor.Error('invalid-user', 'Invalid user', { function: 'RocketChat.saveRoomEncrypted' });
}
await saveRoomEncrypted(rid, encrypted, user);

Type guard

import { isRegisterUser } from '@rocket.chat/core-typings';
// narrows IUser to IRegisterUser when username AND name are defined
const canOperate = (u: IUser): boolean => isRegisterUser(u);

Prevention

When it happens

Trigger: Passing a user stub like { _id } from a method context without fetching the document; bots/apps users lacking name; test fixtures with only _id/username; passing the acting app user instead of the human owner.

Common situations: Server code using Meteor.user() partial projections that omitted name; scripts driving the e2e toggle with hardcoded minimal users.

Related errors


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