RocketChat/Rocket.Chat · error · Meteor.Error

error-room-does-not-exist

error-room-does-not-exist

Error message

This room does not exist

What it means

Thrown by chat.readThread when Rooms.findOneById(thread.rid, ...) returns null - the room referenced by the thread parent message no longer exists in the Rooms collection. Meteor.Error code 'error-room-does-not-exist'. This is a data-integrity edge: the message exists but its room is gone.

Source

Thrown at apps/meteor/server/api/v1/chat.ts:298

		async function action() {
			if (!settings.get<boolean>('Threads_enabled')) {
				throw new Meteor.Error('error-not-allowed', 'Threads Disabled');
			}

			const { tmid } = this.bodyParams;

			const thread = await Messages.findOneById(tmid, { projection: { rid: 1 } });
			if (!thread?.rid) {
				throw new Meteor.Error('error-invalid-message', 'Invalid Message');
			}

			const [user, room] = await Promise.all([
				Users.findOneById(this.userId),
				Rooms.findOneById(thread.rid, { projection: { ...roomAccessAttributes, t: 1, _id: 1 } }),
			]);

			if (!room) {
				throw new Meteor.Error('error-room-does-not-exist', 'This room does not exist');
			}

			if (!user || !(await canAccessRoomAsync(room, user))) {
				throw new Meteor.Error('error-not-allowed', 'Not Allowed');
			}

			await callbacks.run('beforeReadMessages', room._id, user._id);
			await readThread({ user, room, tmid });

			return API.v1.success();
		},
	)
	.post(
		'chat.update',
		{
			authRequired: true,
			body: isChatUpdateProps,
			response: {

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Treat error-room-does-not-exist as a signal to drop the thread from the client (it is orphaned).
  2. Run a data cleanup to remove orphaned messages whose rid no longer resolves.
  3. Investigate room-deletion hooks if orphans recur (beforeDeleteRoom should cascade to messages).

Example fix

// before
try {
  await api.readThread(tmid);
} catch (e) {
  showError(e);
}

// after - gracefully drop orphaned threads
try {
  await api.readThread(tmid);
} catch (e) {
  if (e.error === 'error-room-does-not-exist') {
    removeThreadFromUI(tmid);
    return;
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function threadRoomExists(tmid) {
  const msg = await Messages.findOneById(tmid, { projection: { rid: 1 } });
  if (!msg?.rid) return false;
  const room = await Rooms.findOneById(msg.rid, { projection: { _id: 1 } });
  return Boolean(room);
}

Type guard

function hasResolvableRoom(msg, room) {
  return Boolean(msg && msg.rid && room && room._id === msg.rid);
}

Try / catch

try {
  await api.readThread({ tmid });
} catch (e) {
  if (e.error === 'error-room-does-not-exist') {
    removeOrphanedThread(tmid); // room gone, drop the thread
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: The thread root message exists but its room was deleted (orphan message); rid on the message points to a room id that was purged.

Common situations: Room deletion that did not clean up thread messages; data migration that dropped rooms but kept messages; replica lag in a sharded setup.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/e15c6deac2ebd772. Report an issue: GitHub.