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
- Confirm the room exists and grab its canonical _id via GET /api/v1/rooms.info?roomId=...
- Have the user (or bot) added to the private channel/team before querying mentions
- If banned, the subscription is treated as no access — resolve the ban first
- 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
- Resolve roomIds from rooms.info/rooms.list rather than persisting them long-term
- Invite bots to private rooms before scheduling mention reads
- Treat 'error-not-allowed' as terminal for that room — retrying without membership changes nothing
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.