{"record":{"id":"6633d66ebba9f1b8","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-6633d6","errorCode":"error-not-allowed","errorMessage":"Threads Disabled","messagePattern":"Threads Disabled","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/chat.ts","lineNumber":286,"sourceCode":"\t\t\tresponse: {\n\t\t\t\t400: validateBadRequestErrorResponse,\n\t\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t\t\t200: ajv.compile<void>({\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\tenum: [true],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\trequired: ['success'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tasync function action() {\n\t\t\tif (!settings.get<boolean>('Threads_enabled')) {\n\t\t\t\tthrow new Meteor.Error('error-not-allowed', 'Threads Disabled');\n\t\t\t}\n\n\t\t\tconst { tmid } = this.bodyParams;\n\n\t\t\tconst thread = await Messages.findOneById(tmid, { projection: { rid: 1 } });\n\t\t\tif (!thread?.rid) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-message', 'Invalid Message');\n\t\t\t}\n\n\t\t\tconst [user, room] = await Promise.all([\n\t\t\t\tUsers.findOneById(this.userId),\n\t\t\t\tRooms.findOneById(thread.rid, { projection: { ...roomAccessAttributes, t: 1, _id: 1 } }),\n\t\t\t]);\n\n\t\t\tif (!room) {\n\t\t\t\tthrow new Meteor.Error('error-room-does-not-exist', 'This room does not exist');\n\t\t\t}\n","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/e4b8178b205510181a96ceefee043d0abcd13e5a/apps/meteor/server/api/v1/chat.ts#L268-L304","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ask a workspace admin to enable threads: Administration > Workspace > Settings > Threads > Enable Threads (sets Threads_enabled = true), then retry the call.","If you own the deployment, set the setting programmatically: POST /api/v1/settings/Threads_enabled {\"value\": true} with an admin token, then retry.","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.","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."],"exampleFix":"// before\nawait rc.post('/api/v1/chat.readThread', { tmid });\n// throws { errorType: 'error-not-allowed', error: 'Threads Disabled' }\n\n// after - only call when threads are enabled, catch as fallback\nconst { threadsEnabled } = await rc.get('/api/v1/settings.public?query={\"Threads_enabled\":1}');\nif (threadsEnabled?.['Threads_enabled'] !== false) {\n  await rc.post('/api/v1/chat.readThread', { tmid });\n}","handlingStrategy":"try-catch","validationCode":"const {\n  settings: { threadsEnabled },\n} = await rc.get('/api/v1/settings.public');\nif (!threadsEnabled) skipThreadFeatures();","typeGuard":null,"tryCatchPattern":"try {\n  await rc.post('/api/v1/chat.readThread', { tmid });\n} catch (e) {\n  if (e?.errorType === 'error-not-allowed' && /Threads Disabled/i.test(e.error ?? '')) {\n    markThreadsUnavailable(); // hide thread UI, do not retry\n  } else throw e;\n}","preventionTips":["Read Threads_enabled once at bootstrap and gate every thread endpoint call behind it.","Treat error-not-allowed 'Threads Disabled' as a sticky state - cache it for the session instead of re-probing per request."],"tags":["rocket-chat","rest-api","threads","workspace-setting","chat-readthread","feature-disabled"],"backgroundTag":"workspace-feature-disabled","analyzedSha":"e4b8178b205510181a96ceefee043d0abcd13e5a","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}