RocketChat/Rocket.Chat · error · Error

error-not-allowed

Error message

error-not-allowed

What it means

findMentionedMessages (apps/meteor/server/api/lib/messages.ts) backs GET /api/v1/chat.getMentionedMessages. It first loads the room by roomId and checks canAccessRoomAsync(room, { _id: uid }); if the room does not exist OR the authenticated user cannot access it, it throws plain Error 'error-not-allowed'. Access can fail because the user is not a member of a private channel/team, is banned, or lacks view-history rights on that room type.

Source

Thrown at apps/meteor/server/api/lib/messages.ts:23

import { canAccessRoomAsync } from '../../lib/authorization/canAccessRoom';

export async function findMentionedMessages({
	uid,
	roomId,
	pagination: { offset, count, sort },
}: {
	uid: string;
	roomId: string;
	pagination: { offset: number; count: number; sort: FindOptions<IMessage>['sort'] };
}): Promise<{
	messages: IMessage[];
	count: number;
	offset: number;
	total: number;
}> {
	const room = await Rooms.findOneById(roomId);
	if (!room || !(await canAccessRoomAsync(room, { _id: uid }))) {
		throw new Error('error-not-allowed');
	}
	const user = await Users.findOneById<Pick<IUser, 'username'>>(uid, { projection: { username: 1 } });
	if (!user) {
		throw new Error('invalid-user');
	}

	const { cursor, totalCount } = Messages.findPaginatedVisibleByMentionAndRoomId(user.username, roomId, {
		sort: sort || { ts: -1 },
		skip: offset,
		limit: count,
	});

	const [messages, total] = await Promise.all([cursor.toArray(), totalCount]);

	return {
		messages,
		count: messages.length,
		offset,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Confirm the room exists and grab its canonical _id via GET /api/v1/rooms.info?roomId=...
  2. Have the user (or bot) added to the private channel/team before querying mentions
  3. If banned, the subscription is treated as no access — resolve the ban first
  4. Use an account that already participates in the room for read operations

Example fix

// before
GET /api/v1/chat.getMentionedMessages?roomId=GENERAL-but-mistyped

// after
GET /api/v1/rooms.info?roomName=general               // resolve real _id
GET /api/v1/chat.getMentionedMessages?roomId=GENERAL   // user is a member here
Defensive patterns

Strategy: validation

Validate before calling

async function canAccessRoom(client, roomId: string): Promise<boolean> {
  try {
    const r = await client.get('/api/v1/rooms.info', { params: { roomId } });
    return r.ok; // 404/403 when missing or not a member
  } catch {
    return false;
}
}

Try / catch

try {
  const { data } = await client.get('/api/v1/chat.getMentionedMessages', { params: { roomId } });
} catch (e: any) {
  if ((e?.response?.data?.error ?? '') === 'error-not-allowed') {
    throw new ForbiddenError(`no access to room ${roomId}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /api/v1/chat.getMentionedMessages?roomId=<rid> where rid is wrong/deleted, or where the authed user is not in the private channel or team, or the user's subscription is banned.

Common situations: Bot token expected to read a private room it was never invited to; roomId copied from another workspace; room archived/deleted between calls; testing with a personal token against a private support channel.

Related errors


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