RocketChat/Rocket.Chat · error · Meteor.Error

error-message-editing-blocked

error-message-editing-blocked

Error message

Message editing is blocked

What it means

Thrown by updateMessage when editing is time-blocked: Message_AllowEditing_BlockEditInMinutes is a non-zero number, the user lacks the 'bypass-time-limit-edit-and-delete' permission, and the message's ts is at least that many minutes old. The server recomputes age from originalMessage.ts at submit time, so only edits inside the window succeed.

Source

Thrown at apps/meteor/server/meteor-methods/messages/updateMessage.ts:77

			action: 'Message_editing',
		});
	}

	const blockEditInMinutes = settings.get('Message_AllowEditing_BlockEditInMinutes');
	const bypassBlockTimeLimit = await hasPermissionAsync(uid, 'bypass-time-limit-edit-and-delete', message.rid);

	if (!bypassBlockTimeLimit && Match.test(blockEditInMinutes, Number) && blockEditInMinutes !== 0) {
		let currentTsDiff = 0;
		let msgTs;

		if (originalMessage.ts instanceof Date || Match.test(originalMessage.ts, Number)) {
			msgTs = moment(originalMessage.ts);
		}
		if (msgTs) {
			currentTsDiff = moment().diff(msgTs, 'minutes');
		}
		if (currentTsDiff >= blockEditInMinutes) {
			throw new Meteor.Error('error-message-editing-blocked', 'Message editing is blocked', {
				method: 'updateMessage',
			});
		}
	}

	const user = await Users.findOneById(uid);
	if (!user) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'updateMessage' });
	}
	await canSendMessageAsync(message.rid, { uid: user._id, username: user.username ?? undefined, ...user });

	// It is possible to have an empty array as the attachments property, so ensure both things exist
	if (originalMessage.attachments && originalMessage.attachments.length > 0 && originalMessage.attachments[0].description !== undefined) {
		originalMessage.attachments[0].description = message.msg;
		message.attachments = originalMessage.attachments;
		message.msg = originalMessage.msg;
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Set Message_AllowEditing_BlockEditInMinutes to 0 to disable the time limit (admin setting)
  2. Grant 'bypass-time-limit-edit-and-delete' to roles that must edit old messages (admins, moderators)
  3. Client-side: compute the remaining window from message ts and disable the editor when it expires

Example fix

// before
const canEdit = hasPermission(uid, 'edit-message', rid);

// after
const blockMins = settings.get('Message_AllowEditing_BlockEditInMinutes');
const bypass = hasPermission(uid, 'bypass-time-limit-edit-and-delete', rid);
const withinWindow = bypass || !blockMins || Date.now() - msg.ts.getTime() < blockMins * 60_000;
const canEdit = hasPermission(uid, 'edit-message', rid) || withinWindow;
Defensive patterns

Strategy: validation

Validate before calling

const blockMins = settings.get<number>('Message_AllowEditing_BlockEditInMinutes');
const canStillEdit =
  hasPermission(uid, 'bypass-time-limit-edit-and-delete', msg.rid) ||
  !blockMins ||
  Date.now() - new Date(msg.ts).getTime() < blockMins * 60_000;
if (!canStillEdit) {
  closeEditor(msg);
}

Type guard

const isEditingBlocked = (e: unknown): e is Meteor.Error =>
  typeof e === 'object' && e !== null && (e as { error?: string }).error === 'error-message-editing-blocked';

Try / catch

try {
  await Meteor.callAsync('updateMessage', payload);
} catch (e) {
  if (isEditingBlocked(e)) {
    notifyUser('The edit time window has expired');
    closeEditor();
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Editing a message older than Message_AllowEditing_BlockEditInMinutes without the bypass permission; the window elapsing while an edit form is open, since the server re-checks on save.

Common situations: Compliance-driven workspaces configured with short edit windows; users leaving an editor open past the limit; testing against old seeded messages.

Related errors


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