RocketChat/Rocket.Chat · error · MeteorError

error-federated-users-in-non-federated-rooms

error-federated-users-in-non-federated-rooms

Error message

Cannot add federated users to non-federated rooms

What it means

Thrown from the beforeAddUsersToRoom hook when someone invites usernames that look federated (they pass validateFederatedUsername, i.e. contain a server suffix like 'user@server.tld') into a room that is NOT federated (FederationActions.shouldPerformFederationAction(room) is false). Non-federated rooms physically cannot contain external federated users, so the invite is rejected before any subscription is created.

Solutions

  1. Invite only local usernames (no colon suffix) to the non-federated room
  2. If external users must join, create/use a federated channel so FederationActions.shouldPerformFederationAction(room) is true
  3. Filter the username list before calling the API (see validationCode) so federated handles are routed to a federated room instead

Example fix

// before: mixing external usernames into a local room
await addUsersToRoom(['alice', 'bob@guest.matrix.org'], room, inviter);

// after: route federated usernames to a federated room only
import { validateFederatedUsername } from '@rocket.chat/federation-matrix';
const federated = usernames.filter((u) => validateFederatedUsername(u));
const local = usernames.filter((u) => !validateFederatedUsername(u));
if (federated.length && !isRoomNativeFederated(room)) {
  throw new Error('Use a federated room for: ' + federated.join(', '));
}
await addUsersToRoom(local, room, inviter);
Defensive patterns

Strategy: validation

Validate before calling

import { validateFederatedUsername } from '@rocket.chat/federation-matrix';
import { isRoomNativeFederated } from '@rocket.chat/core-typings';

const canInviteAll = (room: IRoom, usernames: string[]): boolean =>
  isRoomNativeFederated(room) || usernames.every((u) => !validateFederatedUsername(u));

Type guard

import { validateFederatedUsername } from '@rocket.chat/federation-matrix';

const isFederatedUsername = (u: string): boolean => validateFederatedUsername(u);

Try / catch

try {
  await addUsersToRoom(usernames, room, inviter);
} catch (err: any) {
  if (err?.error === 'error-federated-users-in-non-federated-rooms') {
    // split the list: invite local users here, federated ones via a federated room
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling addUsersToRoom / invite with a federated username on a regular local channel; REST API rooms.invite with a federated username targeting a non-federated room; UI invite autocomplete picking a federated user while federation is disabled for that room.

Common situations: Workspace has federation enabled globally but the specific room was created as non-federated; users copy a federated handle from another workspace; scripts that bulk-invite usernames without filtering external ones.

Related errors


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

Appendix: source

Thrown at apps/meteor/ee/server/hooks/federation/index.ts:105

		// deletion came from federation — don't echo
		if (isUserNativeFederated(user)) {
			return;
		}

		if (FederationActions.shouldPerformFederationAction(room)) {
			await FederationMatrix.deleteMessage(room.federation.mrid, message);
		}
	},
	callbacks.priority.MEDIUM,
	'native-federation-after-delete-message',
);

beforeAddUsersToRoom.add(async ({ usernames, inviter }, room) => {
	if (!FederationActions.shouldPerformFederationAction(room) && inviter) {
		// check if trying to invite a federated user to a non-federated room
		const federatedUsernames = usernames.filter((u) => validateFederatedUsername(u));
		if (federatedUsernames.length > 0) {
			throw new MeteorError('error-federated-users-in-non-federated-rooms', 'Cannot add federated users to non-federated rooms');
		}
		return;
	}

	// we create local users before adding them to the room
	await FederationMatrix.ensureFederatedUsersExistLocally(usernames);
});

beforeAddUserToRoom.add(
	async ({ user, inviter }, room) => {
		if (!user.username || !inviter) {
			return;
		}

		if (!FederationActions.shouldPerformFederationAction(room)) {
			return;
		}

View on GitHub (pinned to b2c16d5842)