RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-room
error-invalid-room
Error message
Invalid room
What it means
Thrown by getReadReceiptsFunction when canAccessRoomIdAsync(message.rid, userId) returns false — the calling user is not a member/authorized viewer of the room the message belongs to. Prevents cross-room receipt enumeration. Code is 'error-invalid-room'.
Source
Thrown at apps/meteor/ee/server/meteor-methods/getReadReceipts.ts:33
getReadReceipts(options: { messageId: IMessage['_id'] }): IReadReceiptWithUser[];
}
}
export const getReadReceiptsFunction = async function (messageId: IMessage['_id'], userId: string): Promise<IReadReceiptWithUser[]> {
if (!License.hasModule('message-read-receipt')) {
throw new Meteor.Error('error-action-not-allowed', 'This is an enterprise feature', { method: 'getReadReceipts' });
}
check(messageId, String);
const message = await Messages.findOneById(messageId, { projection: { _id: 1, rid: 1, receiptsArchived: 1 } });
if (!message) {
throw new Meteor.Error('error-invalid-message', 'Invalid message', {
method: 'getReadReceipts',
});
}
if (!(await canAccessRoomIdAsync(message.rid, userId))) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getReadReceipts' });
}
return ReadReceipt.getReceipts(message);
};
Meteor.methods<ServerMethods>({
async getReadReceipts({ messageId }) {
methodDeprecationLogger.method('getReadReceipts', '9.0.0', '/v1/chat.getMessageReadReceipts');
check(messageId, String);
const uid = Meteor.userId();
if (!uid) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getReadReceipts' });
}
return getReadReceiptsFunction(messageId, uid);
},View on GitHub (pinned to f9d3ec372b)
Solutions
- Verify room membership/permission via canAccessRoomIdAsync before exposing the read-receipt action.
- In the UI, only show 'who read this' for rooms the user currently belongs to.
- Treat the error as an authorization failure, not a missing-room error.
Example fix
// before
const receipts = await getReadReceiptsFunction(messageId, uid);
// after
if (!(await canAccessRoomIdAsync(message.rid, uid))) {
throw new Error('Not authorized to view this room');
}
const receipts = await getReadReceiptsFunction(messageId, uid); Defensive patterns
Strategy: validation
Validate before calling
if (!(await canAccessRoomIdAsync(message.rid, uid))) {
throw new Error('Not authorized to view this room');
}
const receipts = await getReadReceiptsFunction(messageId, uid); Try / catch
try {
await getReadReceiptsFunction(messageId, uid);
} catch (e) {
if (isMeteorError(e, 'error-invalid-room')) {
notifyUser('You do not have access to this room.');
return;
}
throw e;
} Prevention
- Verify room access before exposing read-receipt details.
- Only show the action for rooms the user currently belongs to.
- Treat this as authorization, not a missing-room condition.
When it happens
Trigger: A user calls getReadReceipts for a message in a room they cannot access (not a member, banned, different department, private channel they were removed from).
Common situations: User removed from a private room but still has cached message ids; cross-tenant/department data leakage attempt; token/anonymous user hitting a private message.
Related errors
- error-action-not-allowed
- error-invalid-user
- error-not-allowed
- error-action-not-allowed
- error-not-authorized
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/b185a6b7878f58aa.
Report an issue: GitHub.