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

  1. Pass the room's _id string: saveRoomSettings(userId, room._id, settings)
  2. Log typeof rid at the call site and fix the data plumbing that produced a non-string
  3. Mirror the guard client-side: if (typeof rid !== 'string') fail fast before invoking
  4. 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

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


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/7eefd32ca4073ef9. Report an issue: GitHub.