RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

Not allowed

What it means

Rooms.findOneById(rid) returned null, so getUsersOfRoom throws error-not-allowed ('Not allowed'). Despite the message, this exact throw is a not-found condition: no room document with that _id exists on this server. The misleading code comes from reusing error-not-allowed for the missing-room branch.

Source

Thrown at apps/meteor/server/meteor-methods/users/getUsersOfRoom.ts:42

	}
}

Meteor.methods<ServerMethods>({
	async getUsersOfRoom(rid, showAll, { limit, skip } = {}, filter) {
		if (!rid) {
			throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getUsersOfRoom' });
		}

		check(rid, String);

		const userId = Meteor.userId();
		if (!userId) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getUsersOfRoom' });
		}

		const room = await Rooms.findOneById(rid, { projection: { ...roomAccessAttributes, broadcast: 1 } });
		if (!room) {
			throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getUsersOfRoom' });
		}

		if (!(await canAccessRoomAsync(room, { _id: userId }))) {
			throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'getUsersOfRoom' });
		}

		if (room.broadcast && !(await hasPermissionAsync(userId, 'view-broadcast-member-list', rid))) {
			throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getUsersOfRoom' });
		}

		// TODO this is currently counting deactivated users
		const total = await Subscriptions.countByRoomIdWhenUsernameExists(rid);

		const { cursor } = findUsersOfRoom({
			rid,
			status: !showAll ? { $ne: UserStatus.OFFLINE } : undefined,
			limit,
			skip,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Only pass rid values taken from a currently loaded room document
  2. If the room was deleted, clear the cached rid and redirect away from the members view
  3. Verify MONGO_URL / environment so ids resolve against the intended database

Example fix

// before
Meteor.callAsync('getUsersOfRoom', ridFromStorage, showAll);

// after
const room = Rooms.findOne({ _id: ridFromStorage });
if (!room) {
	clearCachedRid();
	return;
}
await Meteor.callAsync('getUsersOfRoom', room._id, showAll);
Defensive patterns

Strategy: try-catch

Validate before calling

const room = Rooms.findOne({ _id: rid });
if (!room) {
	clearCachedRid();
	return;
}
await Meteor.callAsync('getUsersOfRoom', rid, showAll);

Try / catch

try {
	await Meteor.callAsync('getUsersOfRoom', rid, showAll);
} catch (err) {
	if ((err as { error?: string }).error === 'error-not-allowed' && !Rooms.findOne({ _id: rid })) {
		// room does not exist (message is misleading) — purge stale rid
	}
}

Prevention

When it happens

Trigger: Passing a non-existent, typo'd, or already-deleted room id; a rid that belongs to a different workspace (e.g. MONGO_URL pointing at another environment's database).

Common situations: Stale rid cached in localStorage or a bookmarked URL after the room was deleted; room deleted while the tab stayed open; dev ids run against a prod database.

Related errors


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