RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

Not allowed

What it means

getSingleMessage loads the message and then checks canAccessRoomIdAsync(msg.rid, userId); failure throws 'error-not-allowed'. By this point the caller is authenticated and the message exists — the error means specifically: no access to the message's room (private channel / DM without a subscription, or membership revoked).

Source

Thrown at apps/meteor/server/meteor-methods/messages/getSingleMessage.ts:24

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

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		getSingleMessage(mid: IMessage['_id']): Promise<IMessage | null>;
	}
}

export const getSingleMessage = async (userId: string, mid: IMessage['_id']): Promise<IMessage | null> => {
	const msg = await Messages.findOneById(mid);

	if (!msg?.rid) {
		return null;
	}

	if (!(await canAccessRoomIdAsync(msg.rid, userId))) {
		throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getSingleMessage' });
	}

	return msg;
};

Meteor.methods<ServerMethods>({
	async getSingleMessage(mid) {
		check(mid, String);

		const uid = Meteor.userId();

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

		return getSingleMessage(uid, mid);
	},
});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Ensure membership: join the room (or get invited) before fetching its messages
  2. Hide or disable deep links to rooms the user is not subscribed to (check the local Subscriptions collection)
  3. On error, surface a neutral 'message unavailable' response instead of retrying

Example fix

// before
const msg = await Meteor.callAsync('getSingleMessage', mid);

// after
try {
  const msg = await Meteor.callAsync('getSingleMessage', mid);
} catch (e) {
  if (e.error === 'error-not-allowed') {
    // show 'message unavailable', do not retry
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const msg = await Meteor.callAsync('getSingleMessage', mid);
} catch (e) {
  if ((e as Meteor.Error).error === 'error-not-allowed') {
    // message exists but its room is off-limits: show 'unavailable', never retry
  }
}

Prevention

When it happens

Trigger: Meteor.call('getSingleMessage', mid) for a message in a private channel or DM the caller has no subscription to.

Common situations: Deep links (jump-to-message) into private rooms; stale references after membership revocation; bots fetching messages from rooms they never joined.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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