RocketChat/Rocket.Chat · error · Meteor.Error
error-not-allowed
error-not-allowed
Error message
Threads Disabled
What it means
The readThreads Meteor method (deprecated since 9.0.0 in favor of POST /v1/chat.readThread) throws error-not-allowed with message 'Threads Disabled' when either the connection is not authenticated (Meteor.userId() is null) or the workspace setting Threads_enabled is false. Both conditions share one guard, so an unauthenticated call is also reported as 'Threads Disabled', which can mislead debugging.
Source
Thrown at apps/meteor/server/meteor-methods/messages/readThreads.ts:27
import { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';
import { readThread } from '../../lib/messaging/threads/functions';
import { settings } from '../../settings';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
readThreads(tmid: IMessage['_id']): void;
}
}
Meteor.methods<ServerMethods>({
async readThreads(tmid) {
methodDeprecationLogger.method('readThreads', '9.0.0', '/v1/chat.readThread');
check(tmid, String);
if (!Meteor.userId() || !settings.get('Threads_enabled')) {
throw new Meteor.Error('error-not-allowed', 'Threads Disabled', {
method: 'getThreadMessages',
});
}
const thread = await Messages.findOneById(tmid);
if (!thread) {
return;
}
const user = (await Meteor.userAsync()) ?? undefined;
const room = await Rooms.findOneById(thread.rid);
if (!room) {
throw new Meteor.Error('error-room-does-not-exist', 'This room does not exist', { method: 'getThreadMessages' });
}
if (!(await canAccessRoomAsync(room, user))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getThreadMessages' });View on GitHub (pinned to b2c16d5842)
Solutions
- Enable threads: Admin -> Workspace -> Threads (the Threads_enabled setting must be true)
- Ensure the DDP connection is authenticated before calling (Meteor.userId() must return an id)
- Migrate to the supported REST endpoint POST /v1/chat.readThread, the non-deprecated replacement in 9.0.0+
Defensive patterns
Strategy: validation
Validate before calling
// client: gate thread reads on auth + the public Threads_enabled setting
const threadsEnabled = useSetting('Threads_enabled');
if (Meteor.userId() && threadsEnabled) {
await Meteor.callAsync('readThreads', tmid);
} Try / catch
try {
await Meteor.callAsync('readThreads', tmid);
} catch (e: any) {
if (e?.error === 'error-not-allowed' && e?.reason === 'Threads Disabled') {
// threads off OR not logged in: hide thread UI, no retry
return;
}
throw e;
} Prevention
- Read Threads_enabled from the settings subscription before rendering thread UI
- Check Meteor.userId() before any thread method call since both conditions share this error
- Migrate to POST /v1/chat.readThread; the Meteor method is deprecated in 9.0.0
When it happens
Trigger: Meteor.call('readThreads', tmid) while Threads are disabled in Admin -> Workspace -> Threads; the same call from a logged-out DDP connection; test/CI environments running against a fresh database where the Threads_enabled setting was never seeded or explicitly enabled.
Common situations: Workspace admin disabled threads but clients still ship thread UI; upgrade or migration reset the setting to its default; bot or script that never performed a DDP login; automated tests hitting a blank Mongo database.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/af1184591c0d146a.
Report an issue: GitHub.