RocketChat/Rocket.Chat · error · Error

error-invalid-room

error-invalid-room

Error message

error-invalid-room

What it means

Thrown by runVerifyContactChannel (EE contact-channel verification) when LivechatRooms.findOneById(roomId) returns null: the room whose channel is being verified does not exist. The room is needed both for the verification transaction and for the subsequent inquiry/queue handling.

Solutions

  1. Confirm the room still exists before triggering verification (LivechatRooms.findOneById or the room info REST endpoint).
  2. Refresh the client's room reference — the room may be gone; restart the conversation/room as needed.
  3. For API integrations, validate roomId format and existence before invoking the flow.

Example fix

// before
await runVerifyContactChannel(null, { contactId, field, value, visitorId, roomId });

// after
const room = await LivechatRooms.findOneById(roomId);
if (!room) throw new Meteor.Error('error-invalid-room', `Room ${roomId} not found`);
await runVerifyContactChannel(null, { contactId, field, value, visitorId, roomId });
Defensive patterns

Strategy: validation

Validate before calling

const room = await LivechatRooms.findOneById(roomId, { projection: { _id: 1 } });
if (!room) {
	// room deleted or wrong id: do not trigger verification
}

Type guard

const isValidRoomId = async (roomId: string): Promise<boolean> =>
	!!(await LivechatRooms.findOneById(roomId, { projection: { _id: 1 } }));

Try / catch

try {
	await runVerifyContactChannel(null, params);
} catch (e) {
	if (e instanceof Error && e.message === 'error-invalid-room') {
		// reload room list / tell the user the room is gone; no retry will help
	}
	throw e;
}

Prevention

When it happens

Trigger: Triggering the verify contact channel flow with a roomId that was deleted or never existed — e.g. the room was closed/deleted between the client loading it and submitting verification, or a typo'd/stale id is passed by an integration.

Common situations: Omnichannel room deleted by cleanup jobs or an agent while the visitor was verifying, stale client session after room deletion, programmatic callers passing an unvalidated id.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/0b710b57ecd06272. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/ee/server/patches/verifyContactChannel.ts:73

		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);
	if (!room) {
		throw new Error('error-invalid-room');
	}

	const result = await _verifyContactChannel(params, room);

	logger.debug({ msg: 'Finding inquiry', roomId });

	// Note: we are not using the session here since allowing the transactional flow to be used inside the
	//       saveQueueInquiry function would require a lot of changes across the codebase, so if we fail here we
	//       will not be able to rollback the transaction. That is not a big deal since the contact will be properly
	//       merged and the inquiry will be saved in the queue (will need to be taken manually by an agent though).
	const inquiry = await LivechatInquiry.findOneByRoomId(roomId);
	if (!inquiry) {
		// Note: if this happens, something is really wrong with the queue, so we should throw an error to avoid
		//       carrying on a weird state.
		throw new Error('error-invalid-inquiry');
	}

	if (inquiry.status === LivechatInquiryStatus.VERIFYING) {

View on GitHub (pinned to b2c16d5842)