RocketChat/Rocket.Chat · warning

User is already banned from this room

Error message

User is already banned from this room

What it means

The target's subscription already has status 'BANNED' (isBannedSubscription checks subscription.status === 'BANNED'), so re-banning is rejected. Ban state lives on the subscription document; rooms.unbanUser resets it. For callers wanting the user banned, this error means the desired state already holds.

Solutions

  1. Treat the error as success (target state already holds), or call rooms.unbanUser first if a re-ban is intended
  2. Make the UI idempotent: disable the ban action for members already banned
  3. Dedupe retries on the client before resubmitting

Example fix

// before
await POST '/api/v1/rooms.banUser' { roomId, username }; // throws if already banned

// after
try {
  await POST '/api/v1/rooms.banUser' { roomId, username };
} catch (e) {
  if (!String(e.message).includes('already banned')) throw e;
  // already in target state - ok
}
Defensive patterns

Strategy: try-catch

Validate before calling

// if member state is visible in your client, check it first:
if (member.status === 'BANNED' /* or subscription status */) {
  // already banned - no call needed
}

Type guard

import { isBannedSubscription } from '@rocket.chat/core-typings';
// server-side narrowing: (s: ISubscription): s is IBannedSubscription

Try / catch

try {
  await POST '/api/v1/rooms.banUser' { roomId, username };
} catch (e) {
  if (String(e.message).includes('already banned')) {
    // idempotent success - target state already holds
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Double-click or double-submit of the ban action; banning a user already banned by another moderator; retrying after a client timeout when the first call actually succeeded.

Common situations: Non-idempotent moderation UIs; concurrent moderators acting on the same member; at-least-once API clients retrying blindly.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/lib/banUserFromRoom.ts:45

	if (!(await canAccessRoomAsync(room, fromUser))) {
		throw new Error('The required "roomId" or "roomName" param provided does not match any group');
	}

	const bannedUser = await Users.findOneByUsernameIgnoringCase(data.username);
	if (!bannedUser) {
		throw new Error('User not found');
	}

	const subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, bannedUser._id, {
		projection: { _id: 1, status: 1 },
	});
	if (!subscription) {
		throw new Error('User is not in this room');
	}

	// Cannot ban a user who is already banned
	if (isBannedSubscription(subscription)) {
		throw new Error('User is already banned from this room');
	}

	// Cannot ban the last owner
	if (await hasRoleAsync(bannedUser._id, 'owner', room._id)) {
		const numOwners = await Roles.countUsersInRole('owner', room._id);

		if (numOwners === 1) {
			throw new Error('You are the last owner. Please set new owner before banning the user.');
		}
	}

	await banUserFromRoom(data.rid, bannedUser, fromUser);

	return true;
};

View on GitHub (pinned to b2c16d5842)