{"record":{"id":"375e3d2e80f96861","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-375e3d","errorCode":"error-not-allowed","errorMessage":"Not allowed","messagePattern":"Not allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/addRoomModerator.ts","lineNumber":38,"sourceCode":"\t\taddRoomModerator(rid: IRoom['_id'], userId: IUser['_id']): boolean;\n\t}\n}\n\nexport const addRoomModerator = async (fromUserId: IUser['_id'], rid: IRoom['_id'], userId: IUser['_id']): Promise<boolean> => {\n\tcheck(rid, String);\n\tcheck(userId, String);\n\n\tconst room = await Rooms.findOneById(rid, { projection: { t: 1, federated: 1, federation: 1 } });\n\tif (!room) {\n\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\tmethod: 'addRoomModerator',\n\t\t});\n\t}\n\n\tconst isFederated = isRoomFederated(room);\n\n\tif (!(await hasPermissionAsync(fromUserId, 'set-moderator', rid)) && !isFederated) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'addRoomModerator',\n\t\t});\n\t}\n\n\tif (isFederated && !isFederationEnabled()) {\n\t\tthrow new FederationMatrixInvalidConfigurationError('unable to change room owners');\n\t}\n\n\tconst user = await Users.findOneById(userId);\n\n\tif (!user?.username) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'addRoomModerator',\n\t\t});\n\t}\n\n\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/addRoomModerator.ts#L20-L56","documentation":"addRoomModerator authorizes via hasPermissionAsync(fromUserId, 'set-moderator', rid) OR the room being federated (isRoomFederated). error-not-allowed means the caller lacks set-moderator on that room and the room is not federated, so neither branch applies. For federated rooms the permission check is skipped and authority is delegated to the federation flow instead.","triggerScenarios":"A non-moderator calling addRoomModerator (or channels.addModerator/groups.addModerator) on an ordinary non-federated channel; room-scoped set-moderator overrides that exclude the caller.","commonSituations":"Members assuming moderator rights; permission grids trimmed by admins; custom tooling using low-privilege accounts for role changes.","solutions":["Grant set-moderator to the caller's role, globally or scoped to that room.","Use REST channels.addModerator/groups.addModerator with an authorized token.","Catch error-not-allowed and hide the promote action for callers without the permission."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// hide 'Set as moderator' unless the caller holds set-moderator for the room\nif (!(await hasPermission('set-moderator', rid))) {\n\t// do not offer the action\n}","typeGuard":null,"tryCatchPattern":"try {\n\tawait Meteor.callAsync('addRoomModerator', rid, userId);\n} catch (e: any) {\n\tif (e?.error === 'error-not-allowed') {\n\t\t// caller lacks set-moderator and room is not federated: surface auth error\n\t}\n}","preventionTips":["Check set-moderator (room scope) before exposing the promote action.","Remember federated rooms bypass the permission check - expect different behavior there.","Use elevated tokens for automated moderation changes."],"tags":["meteor-methods","authorization","rooms","roles"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}