RocketChat/Rocket.Chat · error · Error
error-verifying-contact-channel
error-verifying-contact-channel
Error message
error-verifying-contact-channel
What it means
Catch-all thrown by _verifyContactChannel in the EE contact-verification patch when the Mongo transaction that verifies a channel and merges contacts fails. The session is aborted, retryable errors (shouldRetryTransaction, e.g. TransientTransactionError) are retried with a decreasing attempt counter, and when retries are exhausted or the error is not retryable, the root cause is logged (msg: 'Error verifying contact channel', with contactId/visitorId/roomId/error) and this generic error is rethrown.
Solutions
- Read the server log entry 'Error verifying contact channel' — the underlying exception is logged there; fix that root cause first.
- Confirm MongoDB runs as a replica set (transactions are unsupported on standalone mongod).
- Retry the whole verify operation after a short backoff — the transaction aborted, so no partial state was left behind.
- If the error is deterministic, inspect the contact/channel documents for corrupt or unexpected state.
Defensive patterns
Strategy: retry
Validate before calling
// environment pre-check: Mongo transactions need a replica set
const hello = await db.admin().command({ hello: 1 });
if (!hello.setName) {
throw new Error('verifyContactChannel requires a MongoDB replica set');
} Try / catch
try {
await runVerifyContactChannel(null, { contactId, field, value, visitorId, roomId });
} catch (e) {
if (e instanceof Error && e.message === 'error-verifying-contact-channel') {
await new Promise((r) => setTimeout(r, backoffMs)); // let concurrent merges finish
return runVerifyContactChannel(null, { contactId, field, value, visitorId, roomId }); // safe: prior txn aborted atomically
}
throw e;
} Prevention
- Run MongoDB as a replica set so transactions are available
- Queue or lock verification per visitor to avoid write conflicts between concurrent merges
- Alert on the logged root-cause error ('Error verifying contact channel' log line), not the wrapper error
When it happens
Trigger: Any exception inside the verify+merge transaction: write conflicts from two agents/visitors merging the same contact concurrently, replica set step-down, Mongo deployed without transaction support (standalone mongod), or invalid contact/channel state surfacing mid-transaction after the built-in retry budget is spent.
Common situations: Concurrent verification of the same visitor from two rooms, MongoDB not running as a replica set, network blips during commit, transaction exceeding timeouts.
Related errors
- error-invalid-channel
- error-removing-visitor
- error-action-not-allowed
- error-contact-channel-blocked
- error-contact-has-no-conflicts
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/437e33311ac7b33f.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/ee/server/patches/verifyContactChannel.ts:53
await LivechatContacts.updateFromUpdaterByAssociation({ visitorId, source: room.source }, updater, { session });
await LivechatRooms.update({ _id: roomId }, { $set: { verified: true } }, { session });
logger.debug({ msg: 'Merging contacts', contactId, visitorId, roomId });
const mergeContactsResult = await mergeContacts(contactId, { visitorId, source: room.source }, session);
await session.commitTransaction();
return mergeContactsResult;
} catch (e) {
await session.abortTransaction();
if (shouldRetryTransaction(e) && attempts > 0) {
logger.debug({ msg: 'Retrying to verify contact channel', contactId, visitorId, roomId });
return _verifyContactChannel(params, room, attempts - 1);
}
logger.error({ msg: 'Error verifying contact channel', contactId, visitorId, roomId, error: e });
throw new Error('error-verifying-contact-channel');
} finally {
await session.endSession();
}
}
export const runVerifyContactChannel = async (
_next: any,
params: {
contactId: string;
field: string;
value: string;
visitorId: string;
roomId: string;
},
): Promise<ILivechatContact | null> => {
const { roomId, contactId, visitorId } = params;
const room = await LivechatRooms.findOneById(roomId);View on GitHub (pinned to b2c16d5842)