RocketChat/Rocket.Chat · error · Error

error-invalid-user

error-invalid-user

Error message

error-invalid-user

What it means

executeUnbanUserFromRoom requires the target user to have a username because the unban flow writes a 'user-unbanned' system message attributed to that username. A user object without username (undefined) triggers Error 'error-invalid-user'.

Source

Thrown at apps/meteor/server/lib/rooms/executeUnbanUserFromRoom.ts:15

import { Message } from '@rocket.chat/core-services';
import { isBannedSubscription, isInviteSubscription, type IUser } from '@rocket.chat/core-typings';
import { Rooms, Subscriptions, Users } from '@rocket.chat/models';

import { afterUnbanFromRoomCallback } from '../callbacks/afterUnbanFromRoomCallback';
import { notifyOnRoomChangedById, notifyOnSubscriptionChanged } from '../notifyListener';

export const executeUnbanUserFromRoom = async function (rid: string, user: IUser, byUser: IUser): Promise<void> {
	const room = await Rooms.findOneById(rid);
	if (!room) {
		throw new Error('error-invalid-room');
	}

	if (!user.username) {
		throw new Error('error-invalid-user');
	}

	const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);
	if (!subscription) {
		throw new Error('error-invalid-subscription');
	}

	// if the subscription is an invite it means we were unbanned and then invited again, then
	// the invite was accepted and we receive a leave event (meaning the user was unbanned), so
	// at this point we just need send the message to say the user was unbanned.
	if (isInviteSubscription(subscription)) {
		await Message.saveSystemMessage('user-unbanned', rid, user.username, user, {
			u: { _id: byUser._id, username: byUser.username },
		});

		return;
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Fetch the full user document (no projection) before the unban call
  2. Ensure the target user has a username (finish custom-auth provisioning) before moderation actions
  3. Type calling-code parameters as Pick<IUser, '_id' | 'username'>

Example fix

// before
await executeUnbanUserFromRoom(rid, user, byUser);

// after
if (!user.username) {
  throw new Meteor.Error('error-invalid-user', 'Target user has no username');
}
await executeUnbanUserFromRoom(rid, user, byUser);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!user.username) {
  throw new Meteor.Error('error-invalid-user', 'Target user has no username');
}
await executeUnbanUserFromRoom(rid, user, byUser);

Type guard

const hasUsername = (user: Pick<IUser, '_id'> | IUser): user is IUser & { username: string } =>
  Boolean(user.username);

Try / catch

try {
  await executeUnbanUserFromRoom(rid, user, byUser);
} catch (err) {
  if (err instanceof Error && err.message === 'error-invalid-user') {
    // re-fetch the full user document and retry once
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a user document fetched with a projection that omits username, or a user record that genuinely has no username (custom auth not yet finalized), into the unban flow.

Common situations: Federation/app code passing partial user objects; user records mid-provisioning; queries using projections like { _id: 1 } reused across features.

Related errors


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