{"record":{"id":"3762f67601ef337e","repo":"RocketChat/Rocket.Chat","slug":"error-federated-users-in-non-federated-rooms","errorCode":"error-federated-users-in-non-federated-rooms","errorMessage":"Cannot add federated users to non-federated rooms","messagePattern":"Cannot add federated users to non-federated rooms","errorType":"error_code","errorClass":"MeteorError","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/hooks/federation/index.ts","lineNumber":105,"sourceCode":"\t\t// deletion came from federation — don't echo\n\t\tif (isUserNativeFederated(user)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (FederationActions.shouldPerformFederationAction(room)) {\n\t\t\tawait FederationMatrix.deleteMessage(room.federation.mrid, message);\n\t\t}\n\t},\n\tcallbacks.priority.MEDIUM,\n\t'native-federation-after-delete-message',\n);\n\nbeforeAddUsersToRoom.add(async ({ usernames, inviter }, room) => {\n\tif (!FederationActions.shouldPerformFederationAction(room) && inviter) {\n\t\t// check if trying to invite a federated user to a non-federated room\n\t\tconst federatedUsernames = usernames.filter((u) => validateFederatedUsername(u));\n\t\tif (federatedUsernames.length > 0) {\n\t\t\tthrow new MeteorError('error-federated-users-in-non-federated-rooms', 'Cannot add federated users to non-federated rooms');\n\t\t}\n\t\treturn;\n\t}\n\n\t// we create local users before adding them to the room\n\tawait FederationMatrix.ensureFederatedUsersExistLocally(usernames);\n});\n\nbeforeAddUserToRoom.add(\n\tasync ({ user, inviter }, room) => {\n\t\tif (!user.username || !inviter) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!FederationActions.shouldPerformFederationAction(room)) {\n\t\t\treturn;\n\t\t}\n","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/hooks/federation/index.ts#L87-L123","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Invite only local usernames (no colon suffix) to the non-federated room","If external users must join, create/use a federated channel so FederationActions.shouldPerformFederationAction(room) is true","Filter the username list before calling the API (see validationCode) so federated handles are routed to a federated room instead"],"exampleFix":"// before: mixing external usernames into a local room\nawait addUsersToRoom(['alice', 'bob@guest.matrix.org'], room, inviter);\n\n// after: route federated usernames to a federated room only\nimport { validateFederatedUsername } from '@rocket.chat/federation-matrix';\nconst federated = usernames.filter((u) => validateFederatedUsername(u));\nconst local = usernames.filter((u) => !validateFederatedUsername(u));\nif (federated.length && !isRoomNativeFederated(room)) {\n  throw new Error('Use a federated room for: ' + federated.join(', '));\n}\nawait addUsersToRoom(local, room, inviter);","handlingStrategy":"validation","validationCode":"import { validateFederatedUsername } from '@rocket.chat/federation-matrix';\nimport { isRoomNativeFederated } from '@rocket.chat/core-typings';\n\nconst canInviteAll = (room: IRoom, usernames: string[]): boolean =>\n  isRoomNativeFederated(room) || usernames.every((u) => !validateFederatedUsername(u));","typeGuard":"import { validateFederatedUsername } from '@rocket.chat/federation-matrix';\n\nconst isFederatedUsername = (u: string): boolean => validateFederatedUsername(u);","tryCatchPattern":"try {\n  await addUsersToRoom(usernames, room, inviter);\n} catch (err: any) {\n  if (err?.error === 'error-federated-users-in-non-federated-rooms') {\n    // split the list: invite local users here, federated ones via a federated room\n  }\n  throw err;\n}","preventionTips":["Filter invite lists with validateFederatedUsername before calling rooms.invite","Make invite UIs distinguish federated handles visually so users pick the right room type","When federation is used heavily, default new channels to federated where appropriate"],"tags":["federation","invites","room-membership","validation"],"backgroundTag":"federation-invite-rejected","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}