RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

Threads Disabled

What it means

Thrown by the POST chat.readThread REST endpoint (apps/meteor/server/api/v1/chat.ts:282) when the workspace setting 'Threads_enabled' is false. It is the very first check in the handler, so it fires before the tmid, room, or permission checks. Rocket.Chat exposes it as an error-not-allowed response, meaning the feature is administratively disabled rather than the caller doing something wrong.

Solutions

  1. Ask a workspace admin to enable threads: Administration > Workspace > Settings > Threads > Enable Threads (sets Threads_enabled = true), then retry the call.
  2. If you own the deployment, set the setting programmatically: POST /api/v1/settings/Threads_enabled {"value": true} with an admin token, then retry.
  3. If threads must stay disabled, stop calling chat.readThread and mark threads as read is not possible; remove the thread-read flow from your integration.
  4. Feature-detect before calling (GET /api/v1/settings.public or cached client config) and hide/disable the thread UI path when Threads_enabled is false.

Example fix

// before
await rc.post('/api/v1/chat.readThread', { tmid });
// throws { errorType: 'error-not-allowed', error: 'Threads Disabled' }

// after - only call when threads are enabled, catch as fallback
const { threadsEnabled } = await rc.get('/api/v1/settings.public?query={"Threads_enabled":1}');
if (threadsEnabled?.['Threads_enabled'] !== false) {
  await rc.post('/api/v1/chat.readThread', { tmid });
}
Defensive patterns

Strategy: try-catch

Validate before calling

const {
  settings: { threadsEnabled },
} = await rc.get('/api/v1/settings.public');
if (!threadsEnabled) skipThreadFeatures();

Try / catch

try {
  await rc.post('/api/v1/chat.readThread', { tmid });
} catch (e) {
  if (e?.errorType === 'error-not-allowed' && /Threads Disabled/i.test(e.error ?? '')) {
    markThreadsUnavailable(); // hide thread UI, do not retry
  } else throw e;
}

Prevention

When it happens

Trigger: POST /api/v1/chat.readThread with body {"tmid": "<thread main message id>"} against a workspace where Administration > Workspace > Settings > Threads is disabled (Threads_enabled = false). Any authenticated user, even a workspace admin issuing the call, gets this error until the setting is turned on.

Common situations: Workspaces that turned threads off for compliance or UX reasons; fresh installs where an admin disabled threads before rolling out to users; integrations/bots written against a threads-enabled workspace later pointed at one where threads were switched off; apps assuming threads are always available.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/api/v1/chat.ts:286

			response: {
				400: validateBadRequestErrorResponse,
				401: validateUnauthorizedErrorResponse,
				200: ajv.compile<void>({
					type: 'object',
					properties: {
						success: {
							type: 'boolean',
							enum: [true],
						},
					},
					required: ['success'],
					additionalProperties: false,
				}),
			},
		},
		async function action() {
			if (!settings.get<boolean>('Threads_enabled')) {
				throw new Meteor.Error('error-not-allowed', 'Threads Disabled');
			}

			const { tmid } = this.bodyParams;

			const thread = await Messages.findOneById(tmid, { projection: { rid: 1 } });
			if (!thread?.rid) {
				throw new Meteor.Error('error-invalid-message', 'Invalid Message');
			}

			const [user, room] = await Promise.all([
				Users.findOneById(this.userId),
				Rooms.findOneById(thread.rid, { projection: { ...roomAccessAttributes, t: 1, _id: 1 } }),
			]);

			if (!room) {
				throw new Meteor.Error('error-room-does-not-exist', 'This room does not exist');
			}

View on GitHub (pinned to e4b8178b20)