RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-room

error-invalid-room

Error message

Invalid room

What it means

dmBlockUserAction resolves the DM, then computes blocked = room.uids?.find(uid => uid !== this.userId). If there is no 'other' user it throws error-invalid-room with method 'im.blockUser'. This fires for self-DMs (only one uid), DMs whose uids array is empty/missing, or odd DM states.

Source

Thrown at apps/meteor/server/api/v1/im.ts:985

		200: ajv.compile<void>({
			type: 'object',
			properties: {
				success: { type: 'boolean', enum: [true] },
			},
			required: ['success'],
			additionalProperties: false,
		}),
	},
} as const;

const dmBlockUserAction = <Path extends string>(_path: Path): TypedAction<typeof dmBlockUserEndpointsProps, Path> =>
	async function action() {
		const { roomId, block } = this.bodyParams;
		const { room } = await findDirectMessageRoom({ roomId }, this.userId);

		const blocked = room.uids?.find((uid) => uid !== this.userId);
		if (!blocked) {
			throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'im.blockUser' });
		}

		if (block) {
			await blockUserMethod(this.userId, { rid: room._id, blocked });
		} else {
			await unblockUserMethod(this.userId, { rid: room._id, blocked });
		}

		return API.v1.success();
	};

const dmEndpoints = API.v1
	.post('im.delete', dmDeleteEndpointsProps, dmDeleteAction('im.delete'))
	.post('dm.delete', dmDeleteEndpointsProps, dmDeleteAction('dm.delete'))
	.post('dm.close', dmCloseEndpointsProps, dmCloseAction('dm.close'))
	.post('im.close', dmCloseEndpointsProps, dmCloseAction('im.close'))
	.post('dm.create', dmCreateEndpointsProps, dmCreateAction('dm.create'))
	.post('im.create', dmCreateEndpointsProps, dmCreateAction('im.create'))

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Confirm the DM actually has a second participant before calling block.
  2. Do not call block on a self-DM.
  3. If the counterpart was removed, re-create the DM (im.create) before blocking.

Example fix

// before
POST /api/v1/im.blockUser { roomId: <self-dm> } // only one uid

// after
const room = await GET /api/v1/im.rooms.info?roomId=<rid>;
if (room.uids.length === 2) {
  await POST /api/v1/im.blockUser { roomId, block: true };
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the DM has a counterpart user before blocking
const room = (await api.get('/api/v1/rooms.info', { params: { roomId } })).data.room;
const others = (room.uids || []).filter(uid => uid !== CURRENT_USER_ID);
if (others.length !== 1) {
  throw new Error('DM has no blockable counterpart user');
}

Type guard

function isBlockableDm(room: unknown, me: string): room is { _id: string; uids: [string, string] } {
  const uids = (room as any)?.uids;
  return Array.isArray(uids) && uids.filter((u: string) => u !== me).length === 1;
}

Try / catch

try {
  await api.post('/api/v1/im.blockUser', { roomId, block: true });
} catch (e) {
  if (e.response?.data?.error === 'error-invalid-room') {
    // self-DM or no counterpart — skip blocking
  } else throw e;
}

Prevention

When it happens

Trigger: POST /api/v1/im.blockUser on a DM that has no counterpart user — e.g. a self-message room, a DM whose other participant was removed leaving a single uid, or a malformed room document without uids.

Common situations: Trying to block yourself (the DM with yourself); the other user was deleted and the room collapsed to one uid; legacy room documents missing the uids field.

Related errors


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