RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

not-allowed

What it means

followMessage throws 'error-not-allowed' ('not-allowed') when the workspace setting Threads_enabled is false — the very first guard in the method. Following a thread only makes sense with threads enabled, so the server short-circuits before looking up the message. This is a configuration gate, not a per-user permission check.

Source

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

import { Meteor } from 'meteor/meteor';

import { RateLimiterClass as RateLimiter } from '../../lib/RateLimiter';
import { canAccessRoomIdAsync } from '../../lib/authorization/canAccessRoom';
import { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';
import { follow } from '../../lib/messaging/threads/functions';
import { notifyOnMessageChange } from '../../lib/notifyListener';
import { settings } from '../../settings';

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		followMessage(message: { mid: IMessage['_id'] }): false | undefined;
	}
}

export const followMessage = async (user: IUser, { mid }: { mid: IMessage['_id'] }): Promise<false | undefined> => {
	if (mid && !settings.get('Threads_enabled')) {
		throw new Meteor.Error('error-not-allowed', 'not-allowed', { method: 'followMessage' });
	}

	const message = await Messages.findOneById(mid);
	if (!message) {
		throw new Meteor.Error('error-invalid-message', 'Invalid message', {
			method: 'followMessage',
		});
	}

	if (!(await canAccessRoomIdAsync(message.rid, user._id))) {
		throw new Meteor.Error('error-not-allowed', 'not-allowed', { method: 'followMessage' });
	}

	const id = message.tmid || message._id;

	const followResult = await follow({ tmid: id, uid: user._id });

	void notifyOnMessageChange({

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Enable Threads: set Threads_enabled to true (Administration settings, or via the settings API) if thread following should work
  2. Gate the follow/unfollow UI on the Threads_enabled setting the server exposes to the client
  3. Once enabled, prefer the deprecation target POST /v1/chat.followMessage over this method

Example fix

// before
Meteor.call('followMessage', { mid });

// after — only offer follow when threads are enabled
if (settings.get('Threads_enabled')) {
  Meteor.call('followMessage', { mid });
}
Defensive patterns

Strategy: validation

Validate before calling

if (!settings.get('Threads_enabled')) {
  // hide follow/unfollow affordances entirely
} else {
  Meteor.call('followMessage', { mid });
}

Try / catch

try {
  await Meteor.callAsync('followMessage', { mid });
} catch (e) {
  if ((e as Meteor.Error).error === 'error-not-allowed') {
    // threads disabled workspace-wide: hide the follow UI, do not retry
  }
}

Prevention

When it happens

Trigger: Calling followMessage({ mid }) (or REST equivalents) on a workspace where an administrator disabled the Threads setting.

Common situations: Workspaces that turn threads off to simplify UX; clients caching capabilities and still showing a 'follow thread' action; admin toggles the setting while clients are connected.

Related errors


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