RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

Not Allowed

What it means

Thrown by the channels online/listing endpoint when canAccessRoomAsync(room, this.user) returns false for the resolved channel. The room exists (a missing room returns a failure string instead), but the calling user lacks access. Uses Meteor.Error with code 'error-not-allowed'.

Source

Thrown at apps/meteor/server/api/v1/channels.ts:1729

		const { _id } = this.queryParams;

		if ((!query || Object.keys(query).length === 0) && !_id) {
			return API.v1.failure('Invalid query');
		}

		const filter = {
			...query,
			...(_id ? { _id } : {}),
			t: 'c',
		};

		const room = await Rooms.findOne(filter as Record<string, any>);
		if (!room) {
			return API.v1.failure('Channel does not exists');
		}

		if (!(await canAccessRoomAsync(room, this.user))) {
			throw new Meteor.Error('error-not-allowed', 'Not Allowed');
		}

		const online: Pick<IUser, '_id' | 'username'>[] = await Users.findUsersNotOffline({
			projection: { username: 1 },
		}).toArray();

		const onlineInRoom = await Promise.all(
			online.map(async (user) => {
				const subscription = await Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, {
					projection: { _id: 1, username: 1 },
				});
				if (subscription) {
					return {
						_id: user._id,
						username: user.username,
					};
				}
			}),

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Ensure the calling user is a member of the channel (or has view-logs/view-room privileges).
  2. Authenticate with a valid token so this.user is populated.
  3. If presence data must be exposed, grant the relevant role a permission like view-outside-room.

Example fix

// before
const room = await Rooms.findOne(filter);
if (!room) {
  return API.v1.failure('Channel does not exists');
}
if (!(await canAccessRoomAsync(room, this.user))) {
  throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}

// after - distinguish unauthenticated from forbidden
if (!this.user) {
  throw new Meteor.Error('error-unauthorized', 'Authentication required');
}
if (!(await canAccessRoomAsync(room, this.user))) {
  throw new Meteor.Error('error-not-allowed', 'You do not have access to this channel');
}
Defensive patterns

Strategy: validation

Validate before calling

// Confirm room access before listing online users
async function canViewChannelOnline(user, roomId) {
  const room = await Rooms.findOneById(roomId);
  if (!room) return false;
  return canAccessRoomAsync(room, user);
}

Type guard

function isAuthedUser(user) {
  return Boolean(user) && typeof user._id === 'string';
}

Try / catch

try {
  await api.channels.online({ roomId });
} catch (e) {
  if (e.error === 'error-not-allowed') {
    promptJoinRoom(roomId); // user is not a member
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the channel online-users endpoint for a channel the user is not a member of, or when not authenticated at all (this.user is null/undefined).

Common situations: Querying presence in a private channel from a non-member; session token expired so this.user is null; integration test using the wrong user fixture.

Related errors


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