RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-room
error-invalid-room
Error message
Invalid room
What it means
Before touching the database, saveRoomSettings asserts Match.test(rid, String); any non-string room id throws error-invalid-room immediately. This is a pure argument-type check, not a lookup — the same code is later reused for the room-not-found case, so distinguish them by when they fire.
Source
Thrown at apps/meteor/server/meteor-methods/rooms/saveRoomSettings.ts:463
export async function saveRoomSettings<RoomSettingName extends keyof RoomSettings>(
userId: IUser['_id'],
rid: IRoom['_id'],
setting: RoomSettingName,
value: RoomSettings[RoomSettingName],
): Promise<{ result: true; rid: IRoom['_id'] }>;
export async function saveRoomSettings(
userId: IUser['_id'],
rid: IRoom['_id'],
settings: Partial<RoomSettings> | keyof RoomSettings,
value?: RoomSettings[keyof RoomSettings],
): Promise<{ result: true; rid: IRoom['_id'] }> {
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
function: 'RocketChat.saveRoomName',
});
}
if (!Match.test(rid, String)) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
method: 'saveRoomSettings',
});
}
if (typeof settings !== 'object') {
settings = {
[settings]: value,
};
}
if (!Object.keys(settings).every((key) => fields.includes(key as keyof typeof settings))) {
throw new Meteor.Error('error-invalid-settings', 'Invalid settings provided', {
method: 'saveRoomSettings',
});
}
const room = await Rooms.findOneById(rid);
View on GitHub (pinned to b2c16d5842)
Solutions
- Pass the room's _id string: saveRoomSettings(userId, room._id, settings)
- Log typeof rid at the call site and fix the data plumbing that produced a non-string
- Mirror the guard client-side: if (typeof rid !== 'string') fail fast before invoking
- Use a type guard or Partial<RoomSettings> typing so the compiler catches the wrong shape
Example fix
// before
Meteor.call('saveRoomSettings', room, { roomTopic: 'x' }); // passed the whole room document
// after
Meteor.call('saveRoomSettings', room._id, { roomTopic: 'x' }); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof rid !== 'string' || rid.length === 0) {
throw new Error(`saveRoomSettings: invalid rid of type ${typeof rid}`);
} Type guard
const isRoomId = (v: unknown): v is string => typeof v === 'string' && v.trim().length > 0;
// usage
if (!isRoomId(rid)) { /* fix the caller before invoking */ } Try / catch
try {
await Meteor.callAsync('saveRoomSettings', rid, settings);
} catch (error) {
if (error instanceof Meteor.Error && error.error === 'error-invalid-room') {
// note: this code covers both non-string rid and room-not-found; log rid and typeof rid to tell them apart
}
} Prevention
- Always pass room._id, never the room document or a computed index
- Type method payloads explicitly so non-string ids fail at compile time
- Validate rid shape at the boundary where it enters your code (API handler, job input)
When it happens
Trigger: Calling saveRoomSettings with rid as a number, undefined, null, an array, or an object — most commonly passing the whole room document instead of room._id, or a rid that is undefined after a failed upstream lookup.
Common situations: Destructuring mistakes (room vs room._id); ids arriving as numbers from external systems; undefined rid from optional chaining gone wrong; placeholder values pasted from examples.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- error-invalid-arguments
- error-invalid-command
- error-invalid-name
- Invalid Selection data provided to the importer.
- error-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/7eefd32ca4073ef9.
Report an issue: GitHub.