{"record":{"id":"8380884bfdcc0581","repo":"RocketChat/Rocket.Chat","slug":"user-is-already-banned-from-this-room","errorCode":null,"errorMessage":"User is already banned from this room","messagePattern":"User is already banned from this room","errorType":"exception","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"apps/meteor/server/lib/banUserFromRoom.ts","lineNumber":45,"sourceCode":"\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);\n\tif (!bannedUser) {\n\t\tthrow new Error('User not found');\n\t}\n\n\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(data.rid, bannedUser._id, {\n\t\tprojection: { _id: 1, status: 1 },\n\t});\n\tif (!subscription) {\n\t\tthrow new Error('User is not in this room');\n\t}\n\n\t// Cannot ban a user who is already banned\n\tif (isBannedSubscription(subscription)) {\n\t\tthrow new Error('User is already banned from this room');\n\t}\n\n\t// Cannot ban the last owner\n\tif (await hasRoleAsync(bannedUser._id, 'owner', room._id)) {\n\t\tconst numOwners = await Roles.countUsersInRole('owner', room._id);\n\n\t\tif (numOwners === 1) {\n\t\t\tthrow new Error('You are the last owner. Please set new owner before banning the user.');\n\t\t}\n\t}\n\n\tawait banUserFromRoom(data.rid, bannedUser, fromUser);\n\n\treturn true;\n};\n","sourceCodeStart":27,"sourceCodeEnd":61,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/banUserFromRoom.ts#L27-L61","documentation":"The target's subscription already has status 'BANNED' (isBannedSubscription checks subscription.status === 'BANNED'), so re-banning is rejected. Ban state lives on the subscription document; rooms.unbanUser resets it. For callers wanting the user banned, this error means the desired state already holds.","triggerScenarios":"Double-click or double-submit of the ban action; banning a user already banned by another moderator; retrying after a client timeout when the first call actually succeeded.","commonSituations":"Non-idempotent moderation UIs; concurrent moderators acting on the same member; at-least-once API clients retrying blindly.","solutions":["Treat the error as success (target state already holds), or call rooms.unbanUser first if a re-ban is intended","Make the UI idempotent: disable the ban action for members already banned","Dedupe retries on the client before resubmitting"],"exampleFix":"// before\nawait POST '/api/v1/rooms.banUser' { roomId, username }; // throws if already banned\n\n// after\ntry {\n  await POST '/api/v1/rooms.banUser' { roomId, username };\n} catch (e) {\n  if (!String(e.message).includes('already banned')) throw e;\n  // already in target state - ok\n}","handlingStrategy":"try-catch","validationCode":"// if member state is visible in your client, check it first:\nif (member.status === 'BANNED' /* or subscription status */) {\n  // already banned - no call needed\n}","typeGuard":"import { isBannedSubscription } from '@rocket.chat/core-typings';\n// server-side narrowing: (s: ISubscription): s is IBannedSubscription","tryCatchPattern":"try {\n  await POST '/api/v1/rooms.banUser' { roomId, username };\n} catch (e) {\n  if (String(e.message).includes('already banned')) {\n    // idempotent success - target state already holds\n  } else {\n    throw e;\n  }\n}","preventionTips":["Make ban actions idempotent: disable them for already-banned members","Dedupe retries after timeouts before resubmitting","Call rooms.unbanUser deliberately when a re-ban cycle is intended"],"tags":["rocket-chat","rooms","moderation","idempotency","subscriptions"],"backgroundTag":"user-already-banned","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}