{"record":{"id":"b968dbae972cd60e","repo":"RocketChat/Rocket.Chat","slug":"error-user-lacks-message-impersonate-permission-b968db","errorCode":"error-user-lacks-message-impersonate-permission","errorMessage":"User selected for the incoming integration lacks the 'message-impersonate' permission.","messagePattern":"User selected for the incoming integration lacks the 'message-impersonate' permission\\.","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts","lineNumber":155,"sourceCode":"\t\t\t!(await Subscriptions.findOneByRoomIdAndUserId(record._id, userId, { projection: { _id: 1 } }))\n\t\t) {\n\t\t\tthrow new Meteor.Error('error-invalid-channel', 'Invalid Channel', {\n\t\t\t\tmethod: 'updateIncomingIntegration',\n\t\t\t});\n\t\t}\n\t}\n\n\tconst username = 'username' in integration ? integration.username : currentIntegration.username;\n\tconst user = await Users.findOneByUsername(username, { projection: { _id: 1, username: 1 } });\n\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-invalid-post-as-user', 'Invalid Post As User', {\n\t\t\tmethod: 'updateIncomingIntegration',\n\t\t});\n\t}\n\n\tif (!(await hasPermissionAsync(user._id, 'message-impersonate'))) {\n\t\tthrow new Meteor.Error(\n\t\t\t'error-user-lacks-message-impersonate-permission',\n\t\t\t\"User selected for the incoming integration lacks the 'message-impersonate' permission.\",\n\t\t\t{\n\t\t\t\tmethod: 'updateIncomingIntegration',\n\t\t\t},\n\t\t);\n\t}\n\n\tconst updatedIntegration = await Integrations.findOneAndUpdate(\n\t\t{ _id: integrationId },\n\t\t{\n\t\t\t$set: {\n\t\t\t\tenabled: integration.enabled,\n\t\t\t\tname: integration.name,\n\t\t\t\t...(typeof integration.avatar !== 'undefined' && { avatar: integration.avatar }),\n\t\t\t\t...(typeof integration.emoji !== 'undefined' && { emoji: integration.emoji }),\n\t\t\t\t...(typeof integration.alias !== 'undefined' && { alias: integration.alias }),\n\t\t\t\t...(channels && { channel: channels }),","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts#L137-L173","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Grant 'message-impersonate' to the target user's role (Administration > Permissions, e.g. add it to the bot role), then retry the update","Or set integration.username to an account that already has the permission, typically the integration's own bot user","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","For automation, use the equivalent REST endpoint POST /v1/integrations.update with an auth token"],"exampleFix":"// before\nawait Meteor.callAsync('updateIncomingIntegration', integrationId, {\n  ...integration,\n  username: 'alice', // alice's role lacks message-impersonate\n});\n\n// after: impersonate a bot user whose role has message-impersonate\nawait Meteor.callAsync('updateIncomingIntegration', integrationId, {\n  ...integration,\n  username: 'my-integration-bot',\n});","handlingStrategy":"validation","validationCode":"// server-side, before updating an incoming integration\nimport { hasPermissionAsync } from '@rocket.chat/core-services';\nimport { Users } from '@rocket.chat/core-server';\n\nconst postAsUsername = payload.username ?? existingIntegration.username;\nconst user = await Users.findOneByUsername(postAsUsername, { projection: { _id: 1 } });\nif (!user || !(await hasPermissionAsync(user._id, 'message-impersonate'))) {\n  // pick another Post As user or grant the permission first\n  throw new Error(`Post As user '${postAsUsername}' cannot be impersonated`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Meteor.callAsync('updateIncomingIntegration', id, payload);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-user-lacks-message-impersonate-permission') {\n    // surface: grant message-impersonate to the Post As user or choose a bot account\n    return;\n  }\n  throw err;\n}","preventionTips":["Keep a dedicated bot user per integration whose role includes message-impersonate","When building Post As pickers, filter the user list to accounts holding message-impersonate","After role or permission changes, re-validate existing integrations' Post As users"],"tags":["integrations","incoming-integrations","permissions","meteor-methods"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}