RocketChat/Rocket.Chat · error · Meteor.Error

invalid-room

invalid-room

Error message

Invalid room

What it means

Thrown by saveRoomReadOnly when Match.test(rid, String) fails (saveRoomReadOnly.ts:14) — the room id is not a string (undefined/null/number/object). Pure argument-type gate ahead of Rooms.setReadOnlyById and the system messages; nothing is modified when it throws. Code 'invalid-room', details { function: 'RocketChat.saveRoomReadOnly' }.

Source

Thrown at apps/meteor/server/lib/rooms/settings/saveRoomReadOnly.ts:14

import { Message } from '@rocket.chat/core-services';
import type { IUser } from '@rocket.chat/core-typings';
import { Rooms } from '@rocket.chat/models';
import { Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

export async function saveRoomReadOnly(
	rid: string,
	readOnly: boolean,
	user: Required<Pick<IUser, '_id' | 'username' | 'name'>>,
	sendMessage = true,
) {
	if (!Match.test(rid, String)) {
		throw new Meteor.Error('invalid-room', 'Invalid room', {
			function: 'RocketChat.saveRoomReadOnly',
		});
	}

	const result = await Rooms.setReadOnlyById(rid, readOnly);

	if (result && sendMessage) {
		if (readOnly) {
			await Message.saveSystemMessage('room-set-read-only', rid, '', user);
		} else {
			await Message.saveSystemMessage('room-removed-read-only', rid, '', user);
		}
	}
	return result;
}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pass the room _id string as the first argument
  2. Validate rid at the method/endpoint boundary before calling
  3. Inspect the caller for missing destructuring or wrong property name
  4. Add a lightweight unit test that non-string rid throws 'invalid-room' early

Example fix

// before
await saveRoomReadOnly(body.rid, readOnly, user);

// after
if (typeof body.rid !== 'string' || body.rid.length === 0) {
	throw new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomReadOnly' });
}
await saveRoomReadOnly(body.rid, readOnly, user);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof rid !== 'string' || rid.length === 0) {
	throw new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomReadOnly' });
}
await saveRoomReadOnly(rid, readOnly, user);

Type guard

const isRoomId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;

Prevention

When it happens

Trigger: saveRoomReadOnly(undefined, true, user) from an unvalidated method payload; passing room document/ObjectId; variable renamed between roomId and rid leaving one call site broken.

Common situations: Channel settings forms with missing hidden rid inputs; REST wrappers forwarding raw body fields; tests using placeholder ids.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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