{"record":{"id":"e0321e77779ab83d","repo":"RocketChat/Rocket.Chat","slug":"error-action-not-allowed-e0321e","errorCode":"error-action-not-allowed","errorMessage":"error-action-not-allowed","messagePattern":"error-action-not-allowed","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/ee/server/api/v1/omnichannel/lib/contacts.ts","lineNumber":18,"sourceCode":"import type { IUser, ILivechatContactVisitorAssociation } from '@rocket.chat/core-typings';\nimport { License } from '@rocket.chat/license';\nimport { LivechatContacts, LivechatRooms, LivechatVisitors } from '@rocket.chat/models';\n\nimport { i18n } from '../../../../../../server/lib/i18n';\nimport { closeRoom } from '../../../../../../server/lib/omnichannel/closeRoom';\n\nexport async function changeContactBlockStatus({ block, visitor }: { visitor: ILivechatContactVisitorAssociation; block: boolean }) {\n\tconst result = await LivechatContacts.setChannelBlockStatus(visitor, block);\n\n\tif (!result.modifiedCount) {\n\t\tthrow new Error('error-contact-not-found');\n\t}\n}\n\nexport function ensureSingleContactLicense() {\n\tif (!License.hasModule('contact-id-verification')) {\n\t\tthrow new Error('error-action-not-allowed');\n\t}\n}\n\nexport async function closeBlockedRoom(association: ILivechatContactVisitorAssociation, user: IUser) {\n\tconst visitor = await LivechatVisitors.findOneById(association.visitorId);\n\n\tif (!visitor) {\n\t\tthrow new Error('error-visitor-not-found');\n\t}\n\n\tconst room = await LivechatRooms.findOneOpenByContactChannelVisitor(association);\n\n\tif (!room) {\n\t\treturn;\n\t}\n\n\treturn closeRoom({ room, visitor, comment: i18n.t('close-blocked-room-comment'), user });\n}","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/api/v1/omnichannel/lib/contacts.ts#L1-L36","documentation":"ensureSingleContactLicense guards the single-contact / contact-identification omnichannel features: when the workspace license lacks the enterprise 'contact-id-verification' module it throws Error('error-action-not-allowed'). Callers of contact registration/merge/block flows hit this before any database work happens.","triggerScenarios":"Calling omnichannel contact endpoints that route through ensureSingleContactLicense on Community edition or a license without the contact-id-verification module.","commonSituations":"Dev instances without EE license; license expired or downgraded; testing contact-center flows on a Community deployment.","solutions":["Activate an enterprise license that includes contact-id-verification","Feature-flag contact-identification calls in your integration until the license is present","On unlicensed workspaces, use plain visitor APIs instead of contact-identification ones"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { License } from '@rocket.chat/license';\n\nif (!License.hasModule('contact-id-verification')) {\n  throw new Error('contact identification features need the contact-id-verification module');\n}\nensureSingleContactLicense(); // proceeds safely","typeGuard":null,"tryCatchPattern":"try {\n  ensureSingleContactLicense();\n} catch (error) {\n  if (error instanceof Error && error.message === 'error-action-not-allowed') {\n    // license guard throws before any work: fail fast with a licensing message\n    throw new LicenseRequiredError('contact-id-verification');\n  }\n  throw error;\n}","preventionTips":["Feature-flag contact-identification flows on the license state","Note this throws a plain Error with the error-action-not-allowed message, not a Meteor.Error","Keep a CE-safe fallback path using plain visitor APIs"],"tags":["enterprise","license","omnichannel","contacts"],"backgroundTag":"enterprise-license-required","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}