RocketChat/Rocket.Chat · error · Error

error-invalid-subscription

error-invalid-subscription

Error message

error-invalid-subscription

What it means

Before unbanning, the code looks up the target's subscription with Subscriptions.findOneByRoomIdAndUserId(rid, user._id). No subscription means the user is not associated with the room at all (banning removes the subscription differently in this design, so a banned user still has one), hence Error 'error-invalid-subscription'.

Source

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

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;
	}

	// if the subscription exists and is not an invite and not banned
	if (!isBannedSubscription(subscription)) {
		throw new Error('error-user-not-banned');
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Treat as idempotent: pre-check the subscription (or catch the error) and report 'already unbanned'
  2. Disable the unban action after first submission to prevent duplicate requests
  3. Refresh the banned-users list from subscription state before offering unban

Example fix

// before
Meteor.call('unbanUserFromRoom', rid, userId);

// after
const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } });
if (!sub) return; // already unbanned / never a member
Meteor.call('unbanUserFromRoom', rid, userId);
Defensive patterns

Strategy: validation

Validate before calling

const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id, { projections: { _id: 1 } });
if (!sub) {
  // user already fully removed — treat as success (idempotent unban)
  return;
}
await executeUnbanUserFromRoom(rid, user, byUser);

Try / catch

try {
  await executeUnbanUserFromRoom(rid, user, byUser);
} catch (err) {
  if (err instanceof Error && err.message === 'error-invalid-subscription') {
    // idempotent case — already unbanned/removed; no-op
  }
  throw err;
}

Prevention

When it happens

Trigger: Unbanning a user who was never in the room, whose subscription was already removed (e.g. unban executed twice, or ban flow deleted the doc), or passing mismatched rid/user._id pairs.

Common situations: Double-click / duplicate unban requests racing after the first one removed state; UI dropdown showing stale banned-user lists after another admin already unbanned; federation events out of order.

Related errors


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