RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room-type

error-invalid-room-type

Error message

${room.t} is not a valid room type

What it means

Before touching subscriptions, unmuteUserInRoom asks the room type's directives whether MUTE is an allowed member action: roomCoordinator.getRoomDirectives(room.t).allowMemberAction(room, RoomMemberActions.MUTE, fromId). When the type disallows it (direct messages, livechat rooms), it throws error-invalid-room-type with the type interpolated into the message, e.g. 'd is not a valid room type'.

Source

Thrown at apps/meteor/server/meteor-methods/rooms/unmuteUserInRoom.ts:35

}

export const unmuteUserInRoom = async (fromId: string, data: { rid: IRoom['_id']; username: string }): Promise<boolean> => {
	if (!fromId || !(await hasPermissionAsync(fromId, 'mute-user', data.rid))) {
		throw new Meteor.Error('error-not-allowed', 'Not allowed', {
			method: 'unmuteUserInRoom',
		});
	}

	const room = await Rooms.findOneById(data.rid);

	if (!room) {
		throw new Meteor.Error('error-invalid-room', 'Invalid room', {
			method: 'unmuteUserInRoom',
		});
	}

	if (!(await roomCoordinator.getRoomDirectives(room.t).allowMemberAction(room, RoomMemberActions.MUTE, fromId))) {
		throw new Meteor.Error('error-invalid-room-type', `${room.t} is not a valid room type`, {
			method: 'unmuteUserInRoom',
			type: room.t,
		});
	}

	const subscription = await Subscriptions.findOneByRoomIdAndUsername(data.rid, data.username, {
		projection: { _id: 1 },
	});

	if (!subscription) {
		throw new Meteor.Error('error-user-not-in-room', 'User is not in this room', {
			method: 'unmuteUserInRoom',
		});
	}

	const unmutedUser = await Users.findOneByUsernameIgnoringCase(data.username);
	if (!unmutedUser?.username) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user to unmute', {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Only offer mute/unmute for room types that support it (channels and private groups)
  2. Check room.t before invoking: skip the call entirely for 'd' and 'l' rooms
  3. For DMs, drop the mute concept — nothing can be muted or unmuted there
  4. When building generic moderation features, query roomCoordinator directives for supported actions per type

Example fix

// before
Meteor.call('unmuteUserInRoom', { rid, username }); // rid is a direct message

// after
const room = roomsCollection.findOne(rid);
if (room && (room.t === 'c' || room.t === 'p')) {
  Meteor.call('unmuteUserInRoom', { rid, username });
}
Defensive patterns

Strategy: type-guard

Validate before calling

// room loaded from the rooms collection before acting
const room = roomsCollection.findOne(rid);
if (!room || !supportsMute(room)) {
  // skip unmute entirely for 'd' (DMs), 'l' (livechat), etc.
}

Type guard

const supportsMute = (room: { t: string }): boolean => room.t === 'c' || room.t === 'p';
// channels and private groups allow the MUTE member action; DMs and livechat rooms do not

Try / catch

try {
  await Meteor.callAsync('unmuteUserInRoom', { rid, username });
} catch (error) {
  if (error instanceof Meteor.Error && error.error === 'error-invalid-room-type') {
    // this room type does not support mute/unmute; remove the action for it
  }
}

Prevention

When it happens

Trigger: Calling Meteor.call('unmuteUserInRoom', { rid, username }) where the room is a direct message (t === 'd') or any other type whose directives do not allow the MUTE member action.

Common situations: Generic moderation tooling applied uniformly to all room types; users muted in a channel whose conversation moves to a DM where unmute is attempted; livechat guest rooms routed through channel moderation code.

Related errors


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