RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-user

error-invalid-user

Error message

Invalid user

What it means

Thrown by the 'e2e.getUsersOfRoomWithoutKey' method wrapper when the DDP connection has no authenticated user. The wrapper resolves Meteor.userId() before any room validation; a null uid aborts the E2E public-key request before room access is even evaluated.

Source

Thrown at apps/meteor/server/meteor-methods/platform/getUsersOfRoomWithoutKey.ts:43

		projection: { 'u._id': 1 },
	}).toArray();
	const userIds = subscriptions.map((s) => s.u._id);
	const options = { projection: { 'e2e.public_key': 1 } };

	const users = await Users.findByIdsWithPublicE2EKey(userIds, options).toArray();

	return {
		users,
	};
};

Meteor.methods<ServerMethods>({
	async 'e2e.getUsersOfRoomWithoutKey'(rid) {
		check(rid, String);

		const userId = Meteor.userId();
		if (!userId) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', {
				method: 'e2e.getUsersOfRoomWithoutKey',
			});
		}

		if (!rid) {
			throw new Meteor.Error('error-invalid-room', 'Invalid room', {
				method: 'e2e.getUsersOfRoomWithoutKey',
			});
		}

		return getUsersOfRoomWithoutKeyMethod(userId, rid);
	},
});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Re-authenticate and restart the E2E key exchange
  2. Guard the call with Meteor.userId() before requesting room member keys
  3. Sequence the handshake to start only after the user session is confirmed

Example fix

// before
const { users } = await Meteor.callAsync('e2e.getUsersOfRoomWithoutKey', rid);

// after
if (!Meteor.userId()) {
  return restartE2EHandshakeAfterLogin();
}
const { users } = await Meteor.callAsync('e2e.getUsersOfRoomWithoutKey', rid);
Defensive patterns

Strategy: validation

Validate before calling

// client: E2E member-key requests require a session
if (!Meteor.userId()) {
  // defer the handshake until after login
}

Type guard

import { Meteor } from 'meteor/meteor';

const isMeteorError = (err: unknown, code?: string): err is Meteor.Error =>
  err instanceof Meteor.Error && (code === undefined || err.error === code);

Try / catch

try {
  const { users } = await Meteor.callAsync('e2e.getUsersOfRoomWithoutKey', rid);
} catch (err) {
  if (isMeteorError(err, 'error-invalid-user')) {
    // re-authenticate, then restart the key exchange
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Running the E2E key handshake from an expired or logged-out session; calling the method during login/logout transitions; automated E2E tests without a seeded user session.

Common situations: Token expiry in long-lived clients during encrypted-room setup; components resuming E2E handshakes before user state loads.

Related errors


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