RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-room
error-invalid-room
Error message
Invalid room
What it means
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'.
Source
Thrown at apps/meteor/server/lib/users/unblockUser.ts:13
import { Subscriptions } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import { notifyOnSubscriptionChangedByRoomIdAndUserIds } from '../notifyListener';
export const unblockUserMethod = async (userId: string, { rid, blocked }: { rid: string; blocked: string }): Promise<void> => {
const [blockedUser, blockerUser] = await Promise.all([
Subscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),
Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),
]);
if (!blockedUser || !blockerUser) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'unblockUser' });
}
const [blockedResponse, blockerResponse] = await Subscriptions.unsetBlockedByRoomId(rid, blocked, userId);
const listenerUsers = [...(blockedResponse?.modifiedCount ? [blocked] : []), ...(blockerResponse?.modifiedCount ? [userId] : [])];
if (listenerUsers.length) {
void notifyOnSubscriptionChangedByRoomIdAndUserIds(rid, listenerUsers);
}
};
View on GitHub (pinned to b2c16d5842)
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
Example fix
// before
await unblockUserMethod(userId, { rid, blocked }); // error-invalid-room after the target left
// after
const [blockedSub, mySub] = await Promise.all([
Subscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),
Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),
]);
if (!blockedSub || !mySub) throw new Meteor.Error('error-invalid-room', 'Invalid room');
await unblockUserMethod(userId, { rid, blocked }); Defensive patterns
Strategy: validation
Validate before calling
import { Subscriptions } from '@rocket.chat/models';
const [target, self] = await Promise.all([
Subscriptions.findOneByRoomIdAndUserId(rid, blocked, { projection: { _id: 1 } }),
Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } }),
]);
if (!target || !self) {
// hide the unblock action; membership changed
} Try / catch
try {
await unblockUserMethod(userId, { rid, blocked });
} catch (error) {
if (error instanceof Meteor.Error && error.error === 'error-invalid-room') {
// refetch subscriptions and update the member list UI
} else {
throw error;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error-user-not-in-room
- error-invalid-subscription
- Room not found
- Subscription not found
- error-invalid-subscription
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/264396c3b78816ca.
Report an issue: GitHub.