RocketChat/Rocket.Chat · error · Error

error-room-cannot-be-closed-try-again

error-room-cannot-be-closed-try-again

Error message

error-room-cannot-be-closed-try-again

What it means

closeRoom performs its closing writes inside a MongoDB transaction with a bounded retry loop for transient errors (shouldRetryTransaction). When the retries are exhausted on a transient error (write conflict, primary stepdown, network blip), it aborts the session and throws Error('error-room-cannot-be-closed-try-again'). The room is left open and consistent - the transaction rolled back cleanly.

Source

Thrown at apps/meteor/server/lib/omnichannel/closeRoom.ts:55

		const { room, closedBy, removedInquiry } = await doCloseRoom(params, session);
		await session.commitTransaction();

		newRoom = room;
		chatCloser = closedBy;
		removedInquiryObj = removedInquiry;
	} catch (e) {
		logger.error({ err: e, msg: 'Failed to close room', afterAttempts: attempts });
		if (session.inTransaction()) {
			await session.abortTransaction();
		}
		// Dont propagate transaction errors
		if (shouldRetryTransaction(e)) {
			if (attempts > 0) {
				logger.debug({ msg: 'Retrying close room because of transient error', attemptsLeft: attempts });
				return closeRoom(params, attempts - 1);
			}

			throw new Error('error-room-cannot-be-closed-try-again');
		}
		throw e;
	} finally {
		await session.endSession();
	}

	// Note: when reaching this point, the room has been closed
	// Transaction is commited and so these messages can be sent here.
	return afterRoomClosed(newRoom, chatCloser, removedInquiryObj, params);
}

async function afterRoomClosed(
	newRoom: IOmnichannelRoom,
	chatCloser: ChatCloser,
	inquiry: ILivechatInquiryRecord | null,
	params: CloseRoomParams,
): Promise<void> {
	if (!chatCloser) {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Retry the close after a short backoff - the error message explicitly says try again
  2. Check MongoDB health: replica set status, primary stability, replication lag
  3. Stagger bulk-close batches instead of firing all closes concurrently
  4. If persistent, inspect logs for the underlying Mongo error (write conflicts, NoSuchTransaction) and resolve the contention source
Defensive patterns

Strategy: retry

Try / catch

const closeWithBackoff = async (params: CloseRoomParams, attempts = 4): Promise<void> => {
  try {
    await closeRoom(params);
  } catch (err: any) {
    if (err?.message === 'error-room-cannot-be-closed-try-again' && attempts > 0) {
      await sleep(2 ** (4 - attempts) * 250); // 250ms, 500ms, 1s, 2s
      return closeWithBackoff(params, attempts - 1);
    }
    throw err;
  }
};

Prevention

When it happens

Trigger: Heavy concurrent writes to the same room/inquiry documents (parallel closes, message bursts) repeatedly causing TransientTransactionError/UnknownTransactionCommitResult; a MongoDB replica set failover or primary stepdown mid-close; a degraded or undersized replica set under load.

Common situations: Bulk-closing many chats at once (e.g. closeOpenChats for agents with huge loads); multi-instance deployments fanning out closes; Mongo under backup/migration pressure; replica sets with lagging secondaries or frequent elections.

Related errors


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