RocketChat/Rocket.Chat · error · Meteor.Error

error-endpoint-disabled

error-endpoint-disabled

Error message

This endpoint is disabled

What it means

Thrown by GET /api/v1/im.messages.others, an admin endpoint that reads other users' direct-message history. The guard at apps/meteor/server/api/v1/im.ts:791 rejects every call unless the workspace setting API_Enable_Direct_Message_History_EndPoint is strictly true; the setting defaults to false (apps/meteor/server/settings/general.ts:9). The check runs before any parameter validation, so even perfectly-formed requests fail while it is off.

Solutions

  1. Enable the setting: Administration -> General -> REST API -> Enable Direct Message History EndPoint, or POST {"value": true} to /api/v1/settings/API_Enable_Direct_Message_History_EndPoint with an admin token
  2. Confirm the caller has view-room-administration, otherwise the next response is 403
  3. If the setting cannot be changed, remove the call - the data is intentionally unavailable on that server

Example fix

# before
 curl -H "X-Auth-Token: $TOKEN" -H "X-User-Id: $UID" \
  "https://chat.example.com/api/v1/im.messages.others?roomId=AbCdEf123"
 # => 400 error-endpoint-disabled

 # after: enable it first (admin token), then call
 curl -X POST -H "X-Auth-Token: $ADMIN_TOKEN" -H "X-User-Id: $ADMIN_UID" \
  -H "Content-Type: application/json" -d '{"value": true}' \
  "https://chat.example.com/api/v1/settings/API_Enable_Direct_Message_History_EndPoint"
 curl -H "X-Auth-Token: $TOKEN" -H "X-User-Id: $UID" \
  "https://chat.example.com/api/v1/im.messages.others?roomId=AbCdEf123"
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await fetch(`${server}/api/v1/settings/API_Enable_Direct_Message_History_EndPoint`, {
  headers: { 'X-Auth-Token': adminToken, 'X-User-Id': adminUserId },
});
const { value } = await res.json();
if (value !== true) {
  throw new Error('im.messages.others is disabled on this server (API_Enable_Direct_Message_History_EndPoint=false)');
}

Try / catch

try {
  const result = await api.get('/api/v1/im.messages.others', { params: { roomId } });
} catch (err) {
  if (err.response?.body?.error === 'error-endpoint-disabled') {
    // permanent config state - surface to operator, never retry
    throw new ConfigurationError('DM history endpoint disabled by workspace setting');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling GET /api/v1/im.messages.others?roomId=... (with an account holding view-room-administration) on any workspace where API_Enable_Direct_Message_History_EndPoint is false or untouched (default). If the caller lacks the permission you get 403 instead and never reach this throw.

Common situations: Fresh installs; compliance-hardened workspaces where the DM-history endpoint was intentionally disabled; scripts developed against a dev server with the flag on and then pointed at production where it is off.

Related errors


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

Appendix: source

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

	required: ['ims', 'offset', 'count', 'total', 'success'],
	additionalProperties: false,
});

const dmMessagesOthersEndpointsProps = {
	authRequired: true as const,
	permissionsRequired: ['view-room-administration'],
	response: {
		200: paginatedMessagesResponseSchema,
		400: validateBadRequestErrorResponse,
		401: validateUnauthorizedErrorResponse,
		403: validateForbiddenErrorResponse,
	},
};

const dmMessagesOthersAction = <Path extends string>(_name: Path): TypedAction<typeof dmMessagesOthersEndpointsProps, Path> =>
	async function action() {
		if (settings.get('API_Enable_Direct_Message_History_EndPoint') !== true) {
			throw new Meteor.Error('error-endpoint-disabled', 'This endpoint is disabled', {
				route: '/api/v1/im.messages.others',
			});
		}

		const { roomId } = this.queryParams;
		if (!roomId) {
			throw new Meteor.Error('error-roomid-param-not-provided', 'The parameter "roomId" is required');
		}

		const room = await Rooms.findOneById<Pick<IRoom, '_id' | 't'>>(roomId, { projection: { _id: 1, t: 1 } });
		if (!room || room?.t !== 'd') {
			throw new Meteor.Error('error-room-not-found', `No direct message room found by the id of: ${roomId}`);
		}

		const { offset, count } = await getPaginationItems(this.queryParams);
		const { sort, fields, query } = await this.parseJsonQuery();
		const ourQuery = Object.assign({}, query, { rid: room._id });

View on GitHub (pinned to e4b8178b20)