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 addIncomingIntegration when the 'post as' user resolves but does not hold the 'message-impersonate' permission. The server checks hasPermissionAsync(user._id, 'message-impersonate') on the TARGET user (the one the webhook posts as), not on the caller. This is a security requirement: an incoming webhook sends messages under this user's identity, so impersonation rights are mandatory.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/incoming/addIncomingIntegration.ts:94

		throw new Meteor.Error('error-invalid-username', 'Invalid username', {
			method: 'addIncomingIntegration',
		});
	}

	if (integration.script?.trim()) {
		validateScriptEngine(integration.scriptEngine ?? 'isolated-vm');
	}

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

	if (!user) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', {
			method: 'addIncomingIntegration',
		});
	}

	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: 'addIncomingIntegration',
			},
		);
	}

	// Default to transpiling with Babel for backwards compatibility; integrations
	// can opt-out per-record by setting `skipTranspile: true` (removed in 9.0.0).
	const skipTranspile = integration.skipTranspile === true;

	const integrationData: IIncomingIntegration = {
		...integration,
		scriptEngine: integration.scriptEngine ?? 'isolated-vm',
		skipTranspile,
		type: 'webhook-incoming',
		channel: channels,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Grant 'message-impersonate' to a role held by the target user: Administration -> Permissions -> message-impersonate, tick the bot/custom role
  2. Or pick a post-as user that already has the permission (e.g. the built-in rocket.cat or a user with admin/bot role that includes it)
  3. As admin you can also run: Meteor.call('authorization:addPermissionToRole', 'message-impersonate', 'bot') then retry

Example fix

// before: target user's role lacks the permission
Meteor.callAsync('addIncomingIntegration', { ...integration, username: 'intern.user' }); // -> error-user-lacks-message-impersonate-permission
// after: grant the permission to the user's role (Administration -> Permissions -> message-impersonate -> check 'bot'), then
Meteor.callAsync('addIncomingIntegration', { ...integration, username: 'ci-bot' }); // ci-bot has role 'bot' with message-impersonate
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await Meteor.callAsync('addIncomingIntegration', integration);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-user-lacks-message-impersonate-permission') {
    // show 'ask an admin to grant message-impersonate to this user's role' and keep form state
  }
}

Prevention

When it happens

Trigger: Choosing a regular employee as the post-as user; creating a bot account whose role lacks message-impersonate; an admin removed message-impersonate from the default bot role as hardening and existing creation flows broke.

Common situations: Fresh workspace where the custom bot role was cloned from User (which lacks the permission); compliance-driven permission lockdowns; integrations built against older Rocket.Chat that did not enforce this check.

Related errors


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