{"record":{"id":"264396c3b78816ca","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-room-264396","errorCode":"error-invalid-room","errorMessage":"Invalid room","messagePattern":"Invalid room","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/users/unblockUser.ts","lineNumber":13,"sourceCode":"import { Subscriptions } from '@rocket.chat/models';\nimport { Meteor } from 'meteor/meteor';\n\nimport { notifyOnSubscriptionChangedByRoomIdAndUserIds } from '../notifyListener';\n\nexport const unblockUserMethod = async (userId: string, { rid, blocked }: { rid: string; blocked: string }): Promise<void> => {\n\tconst [blockedUser, blockerUser] = await Promise.all([\n\t\tSubscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),\n\t\tSubscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),\n\t]);\n\n\tif (!blockedUser || !blockerUser) {\n\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'unblockUser' });\n\t}\n\n\tconst [blockedResponse, blockerResponse] = await Subscriptions.unsetBlockedByRoomId(rid, blocked, userId);\n\n\tconst listenerUsers = [...(blockedResponse?.modifiedCount ? [blocked] : []), ...(blockerResponse?.modifiedCount ? [userId] : [])];\n\n\tif (listenerUsers.length) {\n\t\tvoid notifyOnSubscriptionChangedByRoomIdAndUserIds(rid, listenerUsers);\n\t}\n};\n","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/users/unblockUser.ts#L1-L24","documentation":"unblockUserMethod loads both subscriptions in the room — the blocked user's and the blocker's — via Subscriptions.findOneByRoomIdAndUserId; if either is missing it throws error-invalid-room. Despite the code name, the usual meaning is not 'bad rid' but 'one of the two users is not (or no longer) a member of this room'.","triggerScenarios":"Calling the unblockUser method after the blocked user left the room; using a rid from stale client state (the UI switched rooms); invoking unblock in a context where the caller has no subscription to rid.","commonSituations":"Direct-message member lists kept in client state after the other party leaves; races between leave-room and moderation actions; wiring the rid parameter from the wrong room.","solutions":["Verify both users still have subscriptions in the room before offering the unblock action","Refresh room/membership state from the server when the action fails rather than retrying blindly","Pass rid from the currently open room context, never from persisted state"],"exampleFix":"// before\nawait unblockUserMethod(userId, { rid, blocked }); // error-invalid-room after the target left\n\n// after\nconst [blockedSub, mySub] = await Promise.all([\n  Subscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),\n  Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),\n]);\nif (!blockedSub || !mySub) throw new Meteor.Error('error-invalid-room', 'Invalid room');\nawait unblockUserMethod(userId, { rid, blocked });","handlingStrategy":"validation","validationCode":"import { Subscriptions } from '@rocket.chat/models';\n\nconst [target, self] = await Promise.all([\n  Subscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),\n  Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),\n]);\nif (!target || !self) {\n  // hide the unblock action; membership changed\n}","typeGuard":null,"tryCatchPattern":"try {\n  await unblockUserMethod(userId, { rid, blocked });\n} catch (error) {\n  if (error instanceof Meteor.Error && error.error === 'error-invalid-room') {\n    // refetch subscriptions and update the member list UI\n  } else {\n    throw error;\n  }\n}","preventionTips":["Derive rid from the live room subscription, not cached state","Re-check membership before moderation actions on possibly-stale member lists","Treat this error as 'membership changed', not 'bad room id' — check both users' subscriptions"],"tags":["rooms","subscriptions","blocking","meteor"],"backgroundTag":"room-membership-missing","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}