RocketChat/Rocket.Chat · warning

Could not fetch cluster status for app

Error message

Could not fetch cluster status for app

What it means

GET /api/v1/apps/:id/status augments the local app status with per-instance status from the rest of the deployment: in microservices mode it calls Apps.getAppsStatusInNodes(), otherwise Instance.getAppsStatusInInstances() (internal RPC to other node instances). If that cluster-wide query throws, 'Could not fetch cluster status for app' is logged with the appId and error, and the endpoint still returns 200 containing the local status but no clusterStatus field.

Source

Thrown at apps/meteor/ee/server/apps/communication/rest.ts:1282

			{ authRequired: true, permissionsRequired: ['manage-apps'] },
			{
				async get() {
					const app = manager.getOneById(this.urlParams.id);

					if (!app) {
						return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`);
					}

					const response: { status: AppStatus; clusterStatus?: AppStatusReport[string] } = { status: await app.getStatus() };

					try {
						const clusterStatus = await fetchAppsStatusFromCluster();

						if (clusterStatus?.[app.getID()]) {
							response.clusterStatus = clusterStatus[app.getID()];
						}
					} catch (e) {
						orchestrator.getRocketChatLogger().warn({ msg: 'Could not fetch cluster status for app', appId: app.getID(), err: e });
					}

					return API.v1.success(response);
				},
				async post() {
					const { id: appId } = this.urlParams;
					const { status } = this.bodyParams;

					if (!status || typeof status !== 'string') {
						return API.v1.failure('Invalid status provided, it must be "status" field and a string.');
					}

					const prl = manager.getOneById(appId);
					if (!prl) {
						return API.v1.notFound(`No App found by the id of: ${appId}`);
					}

					if (AppStatusUtils.isEnabled(status)) {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Treat the response as valid but degraded - use status and treat clusterStatus as optional
  2. Check instance/broker health (instance registry, broker connectivity) and restart or wait out the unreachable instance
  3. Retry the status call once the cluster stabilizes
  4. Verify all nodes run compatible versions so the status RPC contract matches
Defensive patterns

Strategy: fallback

Validate before calling

// callers: validate the optional shape before reading cluster info
const isAppStatusReport = (v: unknown): v is Record<string, unknown> =>
	typeof v === 'object' && v !== null && 'status' in v;

Type guard

type AppStatusResponse = { status: string; clusterStatus?: Record<string, { instanceId: string; status: string }[]> };
const hasClusterStatus = (r: AppStatusResponse): r is AppStatusResponse & Required<Pick<AppStatusResponse, 'clusterStatus'>> =>
	r.clusterStatus !== undefined && Object.keys(r.clusterStatus).length > 0;

Try / catch

try {
	const clusterStatus = await fetchAppsStatusFromCluster();
	response.clusterStatus = clusterStatus?.[appId]; // optional enrichment
} catch {
	// degrade gracefully: serve local status only, log for observability
}

Prevention

When it happens

Trigger: Multi-instance deployment where one instance's internal RPC is unreachable or timing out; microservices broker connectivity problems; instances mid-restart when the status is queried; heavy load causing the internal status broadcast to exceed its timeout.

Common situations: Kubernetes pods rolling-restarting; Rocket.Chat running with microservices (broker/DDP-streamer) and a flaky broker; single-instance dev setups with a broken instance registry

Related errors


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