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

  1. Read the server log entry 'Error verifying contact channel' — the underlying exception is logged there; fix that root cause first.
  2. Confirm MongoDB runs as a replica set (transactions are unsupported on standalone mongod).
  3. Retry the whole verify operation after a short backoff — the transaction aborted, so no partial state was left behind.
  4. 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

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


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)