RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-room
error-invalid-room
Error message
Invalid room
What it means
`setRoomKeyIDMethod` throws `error-invalid-room` when `canAccessRoomIdAsync(rid, userId)` returns false: the rid matches no room, or the user cannot access it (not a member of a private room, no access to that room type). Setting a room's E2E key id requires the caller to already have access to the room.
Source
Thrown at apps/meteor/server/meteor-methods/platform/setRoomKeyID.ts:19
import type { IRoom } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Rooms } from '@rocket.chat/models';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import { canAccessRoomIdAsync } from '../../lib/authorization/canAccessRoom';
import { notifyOnRoomChanged } from '../../lib/notifyListener';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
'e2e.setRoomKeyID'(rid: IRoom['_id'], keyID: string): void;
}
}
export const setRoomKeyIDMethod = async (userId: string, rid: IRoom['_id'], keyID: string): Promise<void> => {
if (!(await canAccessRoomIdAsync(rid, userId))) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'e2e.setRoomKeyID' });
}
const room = await Rooms.setE2eKeyId(rid, keyID);
if (!room) {
throw new Meteor.Error('error-room-e2e-key-already-exists', 'E2E Key ID already exists', {
method: 'e2e.setRoomKeyID',
});
}
void notifyOnRoomChanged(room);
};
Meteor.methods<ServerMethods>({
async 'e2e.setRoomKeyID'(rid, keyID) {
check(rid, String);
check(keyID, String);
View on GitHub (pinned to b2c16d5842)
Solutions
- Verify the rid exists and the caller has a subscription to it before invoking
- For private rooms, join/be added first so the access check passes
- Refresh room data on the client before running E2E key operations
Example fix
// before
Meteor.call('e2e.setRoomKeyID', rid, keyID);
// after
const sub = Subscriptions.findOne({ rid });
if (!sub) {
throw new Error('no access to room');
}
Meteor.call('e2e.setRoomKeyID', rid, keyID); Defensive patterns
Strategy: validation
Validate before calling
const sub = Subscriptions.findOne({ rid });
if (!sub) {
throw new Error('user cannot access room');
}
Meteor.call('e2e.setRoomKeyID', rid, keyID); Type guard
const canSubmitRoomKey = (rid: string | undefined, sub: ISubscription | undefined): rid is string => typeof rid === 'string' && rid.length > 0 && !!sub;
Try / catch
try {
await Meteor.callAsync('e2e.setRoomKeyID', rid, keyID);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-invalid-room') {
// rid wrong or no access: refresh room data, verify membership, do not blind-retry
}
} Prevention
- Confirm a subscription exists for the room before E2E key operations
- Reload the room from the server instead of trusting cached rids
- For private rooms, ensure membership before starting key exchange
When it happens
Trigger: `Meteor.call('e2e.setRoomKeyID', rid, keyID)` with a typo'd or deleted rid, or a private room the caller never joined (access check fails even though the room exists).
Common situations: Client state desync — rid taken from a stale cache; room deleted between load and key submission; guest/bot accounts without membership attempting key exchange.
Related errors
- error-not-allowed
- error-room-e2e-key-already-exists
- error-not-allowed
- error-not-allowed
- error-invalid-room
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/ff4883811a27577a.
Report an issue: GitHub.