{"record":{"id":"3ebe17b4338f7346","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-3ebe17","errorCode":"error-not-allowed","errorMessage":"Not allowed","messagePattern":"Not allowed","errorType":"error_code","errorClass":"MeteorError","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/services/room/service.ts","lineNumber":186,"sourceCode":"\tasync saveRoomTopic(\n\t\troomId: string,\n\t\troomTopic: string | undefined,\n\t\tuser: Pick<IUser, 'username' | '_id' | 'federation' | 'federated'>,\n\t\tsendMessage = true,\n\t): Promise<void> {\n\t\tawait saveRoomTopic(roomId, roomTopic, user, sendMessage);\n\t}\n\n\tasync getRouteLink(room: AtLeast<IRoom, '_id' | 't' | 'name'>): Promise<string | boolean> {\n\t\treturn roomCoordinator.getRouteLink(room.t as string, { rid: room._id, name: room.name });\n\t}\n\n\t/**\n\t * Method called by users to join a room.\n\t */\n\tasync join({ room, user, joinCode }: { room: IRoom; user: IUser; joinCode?: string }) {\n\t\tif (!(await roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, user._id))) {\n\t\t\tthrow new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' });\n\t\t}\n\n\t\tif (isOmnichannelRoom(room) && !room.open) {\n\t\t\tthrow new MeteorError('room-closed', 'Room is closed', { method: 'joinRoom' });\n\t\t}\n\n\t\tif (!(await Authorization.canAccessRoom(room, user))) {\n\t\t\tthrow new MeteorError('error-not-allowed', 'Not allowed', { method: 'joinRoom' });\n\t\t}\n\n\t\tif (\n\t\t\tFederationActions.shouldPerformFederationAction(room) &&\n\t\t\t!isUserNativeFederated(user) &&\n\t\t\t!(await FederationMatrix.canUserAccessFederation(user))\n\t\t) {\n\t\t\tthrow new MeteorError('error-not-authorized-federation', 'Not authorized to access federation', { method: 'joinRoom' });\n\t\t}\n","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/services/room/service.ts#L168-L204","documentation":"RoomService.join() first asks the room-type coordinator whether the member action JOIN is allowed: roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, user._id). If the directive for that room type refuses the join for this user, join throws Meteor error-not-allowed ('Not allowed', method 'joinRoom').","triggerScenarios":"Calling join on a room whose type directives disallow user-initiated JOIN — e.g. direct rooms and some omnichannel/custom room types where membership is managed implicitly rather than via join.","commonSituations":"Clients hitting the generic join API for room types that do not support it; custom/EE room types with restrictive member actions; joins that should go through a type-specific flow.","solutions":["Use the membership path intended for that room type (e.g. omnichannel rooms are joined by accepting an inquiry, direct rooms by message exchange)","Check the room type's directives (allowMemberAction for JOIN) before offering a join action to the user","Verify with the room-type configuration/permissions that JOIN is meant to be allowed for this role"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { roomCoordinator } from '/app/lib/rooms/roomCoordinator';\n\nconst allowed = await roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, uid);\nif (!allowed) {\n  // use the room-type-appropriate membership flow instead of join()\n  return useTypeSpecificFlow(room);\n}","typeGuard":"const canJoinRoomType = async (room: IRoom, uid: string): Promise<boolean> =>\n  Boolean(await roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, uid));","tryCatchPattern":"try {\n  await roomService.join({ room, user });\n} catch (err) {\n  if (err?.error === 'error-not-allowed' && err?.details?.method === 'joinRoom') {\n    // room type forbids self-join: use invitation/type-specific flow; retrying join() cannot succeed\n    return notifyUser('This room cannot be joined directly');\n  }\n  throw err;\n}","preventionTips":["Offer join actions only for room types whose directives allow JOIN","Use type-specific membership flows (inquiries for omnichannel, invitations for private rooms)","Check allowMemberAction before calling join()"],"tags":["rooms","join","authorization","room-type","rocket-chat"],"backgroundTag":"missing-permission","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}