{"record":{"id":"ed86edbab43630e8","repo":"RocketChat/Rocket.Chat","slug":"not-allowed-ed86ed","errorCode":null,"errorMessage":"Not allowed","messagePattern":"Not allowed","errorType":"exception","errorClass":null,"httpStatus":400,"severity":"error","filePath":"apps/meteor/server/lib/banUserFromRoom.ts","lineNumber":13,"sourceCode":"import { isBannedSubscription } from '@rocket.chat/core-typings';\nimport { Rooms, Subscriptions, Users, Roles } from '@rocket.chat/models';\n\nimport { canAccessRoomAsync } from './authorization';\nimport { hasPermissionAsync } from './authorization/hasPermission';\nimport { hasRoleAsync } from './authorization/hasRole';\nimport { banUserFromRoom } from './rooms/banUserFromRoom';\nimport { roomCoordinator } from './rooms/roomCoordinator';\nimport { RoomMemberActions } from '../../definition/IRoomTypeConfig';\n\nexport const banUserFromRoomMethod = async (fromId: string, data: { rid: string; username: string }): Promise<boolean> => {\n\tif (!(await hasPermissionAsync(fromId, 'ban-user', data.rid))) {\n\t\tthrow new Error('Not allowed');\n\t}\n\n\tconst room = await Rooms.findOneById(data.rid);\n\n\tif (!room || !(await roomCoordinator.getRoomDirectives(room.t).allowMemberAction(room, RoomMemberActions.BAN, fromId))) {\n\t\tthrow new Error('Not allowed');\n\t}\n\n\tconst fromUser = await Users.findOneById(fromId);\n\tif (!fromUser) {\n\t\tthrow new Error('Invalid user');\n\t}\n\n\tif (!(await canAccessRoomAsync(room, fromUser))) {\n\t\tthrow new Error('The required \"roomId\" or \"roomName\" param provided does not match any group');\n\t}\n\n\tconst bannedUser = await Users.findOneByUsernameIgnoringCase(data.username);","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/banUserFromRoom.ts#L1-L31","documentation":"banUserFromRoomMethod (used by 'POST /api/v1/rooms.banUser' and the '/ban' slash command) throws a plain 'Not allowed' Error when the caller lacks the 'ban-user' permission in that room's scope. Because it is a plain Error rather than Meteor.Error, DDP clients get an opaque internal error; REST clients see the message text. It is the first of several guards in the method.","triggerScenarios":"Calling rooms.banUser with a token whose user lacks 'ban-user'; a moderator role holding the permission only on certain rooms banning elsewhere; running /ban without the permission.","commonSituations":"Custom moderator roles missing ban-user; confusion between global and room-scoped permission grants; testing with a regular user account.","solutions":["Grant 'ban-user' to the acting role, globally or scoped to the room","Check the caller's effective permissions before showing ban actions in the UI","Retry with an admin token to confirm the permission is the cause"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const me = await GET '/api/v1/me';\nif (!me.permissions?.includes('ban-user')) {\n  // hide ban actions for this user (room-scoped grants need per-room checks)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await POST '/api/v1/rooms.banUser' { roomId, username };\n} catch (e) {\n  if (String(e.message).includes('Not allowed')) {\n    // plain Error, no code: first verify 'ban-user' permission, then room-type support\n  } else {\n    throw e;\n  }\n}","preventionTips":["Check effective permissions (global and room-scoped) before showing ban actions","Remember these are plain Errors without codes - match by message","Test custom moderator roles against both permitted and non-permitted rooms"],"tags":["rocket-chat","rooms","moderation","authorization","rbac"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}