RocketChat/Rocket.Chat · error · Meteor.Error

error-user-not-in-room

error-user-not-in-room

Error message

User is not in this room

What it means

Thrown by the 'removeUserFromRoom' Meteor (DDP) method when the target username supplied in data.username does not match any user document at all (Users.findOneByUsernameIgnoringCase returns null). Despite the code 'error-user-not-in-room' and message 'User is not in this room', this specific throw means the user does not exist in the workspace (the lookup is case-insensitive). A different throw at line 72 is the one that actually means 'user exists but has no subscription'. The equivalent REST endpoints are /v1/channels.kick and /v1/groups.kick.

Source

Thrown at apps/meteor/server/meteor-methods/rooms/removeUserFromRoom.ts:60

	const fromUser = await Users.findOneById(fromId);
	if (!fromUser) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', {
			method: 'removeUserFromRoom',
		});
	}

	// did this way so a ctrl-f would find the permission being used
	const kickAnyUserPermission = room.t === 'c' ? 'kick-user-from-any-c-room' : 'kick-user-from-any-p-room';

	const canKickAnyUser = await hasPermissionAsync(fromId, kickAnyUserPermission);
	if (!canKickAnyUser && !(await canAccessRoomAsync(room, fromUser))) {
		throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "roomName" param provided does not match any group');
	}

	const removedUser = await Users.findOneByUsernameIgnoringCase(data.username);
	if (!removedUser) {
		throw new Meteor.Error('error-user-not-in-room', 'User is not in this room', {
			method: 'removeUserFromRoom',
		});
	}

	await Room.beforeUserRemoved(room);

	if (!canKickAnyUser) {
		const subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, removedUser._id, {
			projection: { _id: 1 },
		});
		if (!subscription) {
			throw new Meteor.Error('error-user-not-in-room', 'User is not in this room', {
				method: 'removeUserFromRoom',
			});
		}
	}

	if (await hasRoleAsync(removedUser._id, 'owner', room._id)) {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Verify the username exists before calling (e.g. GET /api/v1/users.info?username=..., or check the room member list) and send the exact, current username.
  2. Trim/normalize the username string and confirm you are not accidentally passing userId or an email address.
  3. Handle this error as a non-retryable no-op in idempotent automation: the user cannot be in the room if they do not exist.
  4. If the username was recently changed, fetch the fresh username from the room's subscription/member data instead of caching it.

Example fix

// before
Meteor.call('removeUserFromRoom', { rid, username: 'john.doe ' }); // typo/whitespace -> error-user-not-in-room

// after
const username = rawUsername.trim();
const info = await fetch(`/api/v1/users.info?username=${encodeURIComponent(username)}`); // 400 'user-not-found' if missing
if (!info.ok) throw new Error(`No such user: ${username}`);
Meteor.call('removeUserFromRoom', { rid, username: info.user.username });
Defensive patterns

Strategy: validation

Validate before calling

// Resolve and verify the username before kicking
const normalized = String(username).trim();
const res = await fetch(`/api/v1/users.info?username=${encodeURIComponent(normalized)}`, { headers: authHeaders });
if (!res.ok) {
  throw new Error(`Cannot remove: no user '${normalized}' exists in this workspace`);
}
const { user } = await res.json(); // use user.username (canonical case)
await kick(rid, user.username);

Type guard

const isValidUsername = (u: unknown): u is string =>
  typeof u === 'string' && u.trim().length > 0 && !u.includes(' ') && !/.+@.+\..+/.test(u) && u !== 'me';

Try / catch

try {
  await Meteor.callAsync('removeUserFromRoom', { rid, username });
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-user-not-in-room') {
    // Distinguish: 1540 means the user does not exist at all
    console.warn(`User '${username}' not found; nothing to remove`);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling Meteor.call('removeUserFromRoom', { rid, username }) or removeUserFromRoomMethod(fromId, data) where username is misspelled, belongs to a deleted user, or the account was renamed. Also triggered when data.username is an empty string or contains whitespace, since the exact (case-insensitive) string is used for the lookup.

Common situations: Stale client UI still showing a removed/deleted member after the user was deleted server-side; bots or integrations kicking by an outdated username after a rename; copy/paste of usernames with trailing spaces; passing a user _id or email instead of the username.

Related errors


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