RocketChat/Rocket.Chat · error · Meteor.Error
error-not-allowed
error-not-allowed
Error message
not-allowed
What it means
If the message carries a tmid (thread reply) but the workspace setting Threads_enabled is false, executeSendMessage throws error-not-allowed. The whole thread feature is off server-side, so any thread-addressed send is rejected regardless of room or permissions.
Source
Thrown at apps/meteor/server/meteor-methods/messages/sendMessage.ts:44
* @param extraInfo
* - ts: The timestamp of the message. the message object already has a ts, but this value is validated and only a window of 10 seconds is allowed to be used. this value overrides the message.ts value without validation.
*
*
* @returns
*/
export async function executeSendMessage(
uid: IUser['_id'] | IUser,
message: AtLeast<IMessage, 'rid'>,
extraInfo?: { ts?: Date; previewUrls?: string[] },
) {
if (message.tshow && !message.tmid) {
throw new Meteor.Error('invalid-params', 'tshow provided but missing tmid', {
method: 'sendMessage',
});
}
if (message.tmid && !settings.get('Threads_enabled')) {
throw new Meteor.Error('error-not-allowed', 'not-allowed', {
method: 'sendMessage',
});
}
const isTimestampFromClient = Boolean(!extraInfo?.ts && message.ts);
const now = new Date();
message.ts = extraInfo?.ts ?? message.ts ?? now;
if (isTimestampFromClient) {
const tsDiff = Math.abs(moment(message.ts).diff(Date.now()));
if (tsDiff > 60000) {
throw new Meteor.Error('error-message-ts-out-of-sync', 'Message timestamp is out of sync', {
method: 'sendMessage',
message_ts: message.ts,
server_ts: new Date().getTime(),
});
}
if (tsDiff > 10000) {
message.ts = now;View on GitHub (pinned to b2c16d5842)
Solutions
- Enable threads: Admin -> Workspace -> Threads (Threads_enabled)
- Client-side: read the threads setting and disable thread UI before a tmid can be attached
- Fall back to a plain message without tmid when threads are disabled
Example fix
// before
await Meteor.callAsync('sendMessage', { rid, msg, tmid });
// after: strip thread fields when the feature is off
const threadsEnabled = settings.get('Threads_enabled');
await Meteor.callAsync('sendMessage', { rid, msg, ...(threadsEnabled ? { tmid } : {}) }); Defensive patterns
Strategy: validation
Validate before calling
// client: only attach thread fields when threads are enabled
const threadsEnabled = settings.get('Threads_enabled');
const payload = { rid, msg, ...(threadsEnabled && tmid ? { tmid } : {}) };
await Meteor.callAsync('sendMessage', payload); Try / catch
try {
await Meteor.callAsync('sendMessage', { rid, msg, tmid });
} catch (e: any) {
if (e?.error === 'error-not-allowed') {
// threads disabled: resend as a plain message without tmid
await Meteor.callAsync('sendMessage', { rid, msg });
return;
}
throw e;
} Prevention
- Subscribe to the Threads_enabled setting and gate thread UI on it
- Strip tmid/tshow when the setting flips to false
- Watch for admin setting changes via the settings subscription, not a boot-time snapshot
When it happens
Trigger: Client with cached thread UI sends a reply with tmid after an admin disabled threads; bot or integration hardcoded to thread its messages on a workspace where threads are off; fresh install where Threads_enabled defaults to false.
Common situations: Setting flipped after clients loaded thread UI; sandbox/test workspace without threads enabled; automation written against a threaded workspace reused on a non-threaded one.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/9679c2db58201d68.
Report an issue: GitHub.