RocketChat/Rocket.Chat · error · Meteor.Error

error-user-lacks-message-impersonate-permission

error-user-lacks-message-impersonate-permission

Error message

User selected for the incoming integration lacks the 'message-impersonate' permission.

What it means

Thrown by updateIncomingIntegration when the user configured as the integration's 'Post As' account lacks the 'message-impersonate' permission. The server resolves integration.username (falling back to the stored integration's username) via Users.findOneByUsername, then checks hasPermissionAsync(user._id, 'message-impersonate') before persisting the update. Incoming integrations post canal messages impersonating that user, so the explicit permission gate applies to the impersonated account, not the caller.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts:155

			!(await Subscriptions.findOneByRoomIdAndUserId(record._id, userId, { projection: { _id: 1 } }))
		) {
			throw new Meteor.Error('error-invalid-channel', 'Invalid Channel', {
				method: 'updateIncomingIntegration',
			});
		}
	}

	const username = 'username' in integration ? integration.username : currentIntegration.username;
	const user = await Users.findOneByUsername(username, { projection: { _id: 1, username: 1 } });

	if (!user) {
		throw new Meteor.Error('error-invalid-post-as-user', 'Invalid Post As User', {
			method: 'updateIncomingIntegration',
		});
	}

	if (!(await hasPermissionAsync(user._id, 'message-impersonate'))) {
		throw new Meteor.Error(
			'error-user-lacks-message-impersonate-permission',
			"User selected for the incoming integration lacks the 'message-impersonate' permission.",
			{
				method: 'updateIncomingIntegration',
			},
		);
	}

	const updatedIntegration = await Integrations.findOneAndUpdate(
		{ _id: integrationId },
		{
			$set: {
				enabled: integration.enabled,
				name: integration.name,
				...(typeof integration.avatar !== 'undefined' && { avatar: integration.avatar }),
				...(typeof integration.emoji !== 'undefined' && { emoji: integration.emoji }),
				...(typeof integration.alias !== 'undefined' && { alias: integration.alias }),
				...(channels && { channel: channels }),

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Grant 'message-impersonate' to the target user's role (Administration > Permissions, e.g. add it to the bot role), then retry the update
  2. Or set integration.username to an account that already has the permission, typically the integration's own bot user
  3. If the payload omits username, remember the stored username is re-checked — fix that integration's Post As user or grant the permission and submit again
  4. For automation, use the equivalent REST endpoint POST /v1/integrations.update with an auth token

Example fix

// before
await Meteor.callAsync('updateIncomingIntegration', integrationId, {
  ...integration,
  username: 'alice', // alice's role lacks message-impersonate
});

// after: impersonate a bot user whose role has message-impersonate
await Meteor.callAsync('updateIncomingIntegration', integrationId, {
  ...integration,
  username: 'my-integration-bot',
});
Defensive patterns

Strategy: validation

Validate before calling

// server-side, before updating an incoming integration
import { hasPermissionAsync } from '@rocket.chat/core-services';
import { Users } from '@rocket.chat/core-server';

const postAsUsername = payload.username ?? existingIntegration.username;
const user = await Users.findOneByUsername(postAsUsername, { projection: { _id: 1 } });
if (!user || !(await hasPermissionAsync(user._id, 'message-impersonate'))) {
  // pick another Post As user or grant the permission first
  throw new Error(`Post As user '${postAsUsername}' cannot be impersonated`);
}

Try / catch

try {
  await Meteor.callAsync('updateIncomingIntegration', id, payload);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-user-lacks-message-impersonate-permission') {
    // surface: grant message-impersonate to the Post As user or choose a bot account
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Meteor call to updateIncomingIntegration(integrationId, integration) where integration.username — or the previously stored username when the payload omits it — names a user whose roles do not include 'message-impersonate'; also fires when an admin revokes that permission from the bot role after the integration was created.

Common situations: Selecting a regular (non-bot) user as Post As, since by default only bot-like roles carry message-impersonate; migrating integrations between workspaces with different role definitions; role/permission audits that strip message-impersonate from the bot role.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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