{"record":{"id":"929ab0d868923d7e","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-channel","errorCode":null,"errorMessage":"error-invalid-channel","messagePattern":"error-invalid-channel","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/patches/mergeContacts.ts","lineNumber":25,"sourceCode":"import { notifyOnSettingChanged } from '../../../server/lib/notifyListener';\nimport { ContactMerger } from '../../../server/lib/omnichannel/contacts/ContactMerger';\nimport { mergeContacts } from '../../../server/lib/omnichannel/contacts/mergeContacts';\nimport { contactLogger as logger } from '../lib/omnichannel/logger';\n\nexport const runMergeContacts = async (\n\t_next: any,\n\tcontactId: string,\n\tvisitor: ILivechatContactVisitorAssociation,\n\tsession?: ClientSession,\n): Promise<ILivechatContact | null> => {\n\tconst originalContact = await LivechatContacts.findOneEnabledById(contactId, { session });\n\tif (!originalContact) {\n\t\tthrow new Error('error-invalid-contact');\n\t}\n\n\tconst channel = originalContact.channels.find((channel: ILivechatContactChannel) => isSameChannel(channel.visitor, visitor));\n\tif (!channel) {\n\t\tthrow new Error('error-invalid-channel');\n\t}\n\n\tlogger.debug({ msg: 'Getting similar contacts', contactId });\n\n\tconst similarContacts: ILivechatContact[] = await LivechatContacts.findSimilarVerifiedContacts(channel, contactId, { session });\n\n\tif (!similarContacts.length) {\n\t\tlogger.debug({ msg: 'No similar contacts found', contactId });\n\t\treturn originalContact;\n\t}\n\n\tlogger.debug({ msg: 'Found contacts to merge', contactId, count: similarContacts.length });\n\tfor await (const similarContact of similarContacts) {\n\t\tconst fields = ContactMerger.getAllFieldsFromContact(similarContact);\n\t\tawait ContactMerger.mergeFieldsIntoContact({ fields, contact: originalContact, session });\n\t}\n\n\tconst similarContactIds = similarContacts.map((c) => c._id);","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/patches/mergeContacts.ts#L7-L43","documentation":"Thrown by runMergeContacts when the original contact exists but none of its channels match the supplied visitor association (isSameChannel returns false for every channel). The merge is driven by a channel, so without a matching channel the code cannot reconcile the visitor with the contact and aborts inside the transaction.","triggerScenarios":"Calling mergeContacts with a visitor whose source/visitorId/token does not line up with any channel.visitor on the contact; visitor came from a different channel type than any channel on the contact.","commonSituations":"Visitor association built with the wrong source type (e.g. 'api' vs 'web'); visitorId changed after a reconnect; contact channel was unverified/removed; cross-channel merge attempted where no channel overlap exists.","solutions":["Verify the visitor's source and visitorId match a channel.visitor on the contact before calling mergeContacts.","If the channel is missing, add/verify it on the contact first via the contact-channel verification flow.","Ensure isSameChannel semantics (source + visitorId) are consistent with how the channel was originally created.","Log the supplied visitor vs the contact.channels to find the mismatch."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function findMatchingChannel(contact: ILivechatContact, visitor: ILivechatContactVisitorAssociation): ILivechatContactChannel | undefined {\n  return contact.channels.find((ch) => isSameChannel(ch.visitor, visitor));\n}\n// if (!findMatchingChannel(contact, visitor)) throw new Error('Visitor does not match any channel');","typeGuard":null,"tryCatchPattern":"try {\n  await mergeContacts(contactId, visitor, session);\n} catch (e) {\n  if (e.message === 'error-invalid-channel') {\n    // verify/add the channel before retrying the merge\n  } else throw e;\n}","preventionTips":["Ensure the visitor source matches one of the contact's channel sources before merge.","Standardize visitorId assignment so reconnects do not break channel matching.","Add a channel-verification step in the UI before triggering a merge."],"tags":["omnichannel","contacts","channel","merge","validation"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}