RocketChat/Rocket.Chat · error · MeteorError

error-max-guests-number-reached

error-max-guests-number-reached

Error message

Maximum number of guests reached.

What it means

Thrown by validateUserRoles when a user is being changed into a guest (roles === ['guest'] where they were not previously a guest) and License.shouldPreventAction('guestUsers') is true — i.e. the enterprise license's guest-user quota is exhausted. MeteorError code 'error-max-guests-number-reached', method 'insertOrUpdateUser', field 'Assign_role'. Apps and bots (isSpecialType) short-circuit before this check.

Source

Thrown at apps/meteor/ee/server/lib/authorization/validateUserRoles.ts:26

	const isApp = Boolean(userData.type === 'app');
	const wasApp = Boolean(currentUserData?.type === 'app');

	const isBot = Boolean(userData.type === 'bot');
	const wasBot = Boolean(currentUserData?.type === 'bot');

	const isGuest = Boolean(userData.roles?.includes('guest') && userData.roles.length === 1);
	const wasGuest = Boolean(currentUserData?.roles?.includes('guest') && currentUserData.roles.length === 1);

	const isSpecialType = isApp || isBot;

	const hasGuestToChanged = isGuest && !wasGuest;

	if (isSpecialType) {
		return;
	}

	if (hasGuestToChanged && (await License.shouldPreventAction('guestUsers'))) {
		throw new MeteorError('error-max-guests-number-reached', 'Maximum number of guests reached.', {
			method: 'insertOrUpdateUser',
			field: 'Assign_role',
		});
	}

	if (isGuest) {
		return;
	}

	const isActive = Boolean(userData.active !== false);
	const wasActive = currentUserData && currentUserData?.active !== false;

	const hasRemovedSpecialType = (wasApp && !isApp) || (wasBot && !isBot);

	if (!isActive) {
		return;
	}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Free up a guest seat by converting an existing guest to a regular user or deactivating them, then retry.
  2. Upgrade the license to raise the guestUsers cap.
  3. If the conversion is not required, keep the user as a regular user instead of demoting to guest.
  4. Before bulk operations, check current guest count against the license limit.

Example fix

// before: demote beyond limit
await Users.updateOne({ _id }, { $set: { roles: ['guest'] } });
await validateUserRoles({ roles: ['guest'] }, currentUserData);

// after: verify headroom first
if (await License.shouldPreventAction('guestUsers')) {
  throw new Error('Convert an existing guest first or upgrade the license');
}
Defensive patterns

Strategy: validation

Validate before calling

async function canDemoteToGuest(): Promise<boolean> {
  return !(await License.shouldPreventAction('guestUsers'));
}

Type guard

const isGuestOnly = (roles: unknown): roles is ['guest'] =>
  Array.isArray(roles) && roles.length === 1 && roles[0] === 'guest';

Try / catch

try { await validateUserRoles({ roles: ['guest'] }, current); } catch (e) {
  if (e?.error === 'error-max-guests-number-reached') { /* free a seat or upgrade */ } else throw e;
}

Prevention

When it happens

Trigger: Admin assigns the 'guest' role to a previously non-guest user (demoting them) when the guest quota is full; bulk user import that converts users to guests beyond the limit; UI 'Assign_role' action that flips a user to guest-only.

Common situations: License downgrade reduced the guest allowance; trial license guest seats exhausted; org converted many users to guests for a partner rollout.

Related errors


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