{"record":{"id":"854bdef8ef4d4ba6","repo":"RocketChat/Rocket.Chat","slug":"could-not-fetch-cluster-status-for-app","errorCode":null,"errorMessage":"Could not fetch cluster status for app","messagePattern":"Could not fetch cluster status for app","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"apps/meteor/ee/server/apps/communication/rest.ts","lineNumber":1282,"sourceCode":"\t\t\t{ authRequired: true, permissionsRequired: ['manage-apps'] },\n\t\t\t{\n\t\t\t\tasync get() {\n\t\t\t\t\tconst app = manager.getOneById(this.urlParams.id);\n\n\t\t\t\t\tif (!app) {\n\t\t\t\t\t\treturn API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst response: { status: AppStatus; clusterStatus?: AppStatusReport[string] } = { status: await app.getStatus() };\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst clusterStatus = await fetchAppsStatusFromCluster();\n\n\t\t\t\t\t\tif (clusterStatus?.[app.getID()]) {\n\t\t\t\t\t\t\tresponse.clusterStatus = clusterStatus[app.getID()];\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\torchestrator.getRocketChatLogger().warn({ msg: 'Could not fetch cluster status for app', appId: app.getID(), err: e });\n\t\t\t\t\t}\n\n\t\t\t\t\treturn API.v1.success(response);\n\t\t\t\t},\n\t\t\t\tasync post() {\n\t\t\t\t\tconst { id: appId } = this.urlParams;\n\t\t\t\t\tconst { status } = this.bodyParams;\n\n\t\t\t\t\tif (!status || typeof status !== 'string') {\n\t\t\t\t\t\treturn API.v1.failure('Invalid status provided, it must be \"status\" field and a string.');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst prl = manager.getOneById(appId);\n\t\t\t\t\tif (!prl) {\n\t\t\t\t\t\treturn API.v1.notFound(`No App found by the id of: ${appId}`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (AppStatusUtils.isEnabled(status)) {","sourceCodeStart":1264,"sourceCodeEnd":1300,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/apps/communication/rest.ts#L1264-L1300","documentation":"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.","triggerScenarios":"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.","commonSituations":"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","solutions":["Treat the response as valid but degraded - use status and treat clusterStatus as optional","Check instance/broker health (instance registry, broker connectivity) and restart or wait out the unreachable instance","Retry the status call once the cluster stabilizes","Verify all nodes run compatible versions so the status RPC contract matches"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// callers: validate the optional shape before reading cluster info\nconst isAppStatusReport = (v: unknown): v is Record<string, unknown> =>\n\ttypeof v === 'object' && v !== null && 'status' in v;","typeGuard":"type AppStatusResponse = { status: string; clusterStatus?: Record<string, { instanceId: string; status: string }[]> };\nconst hasClusterStatus = (r: AppStatusResponse): r is AppStatusResponse & Required<Pick<AppStatusResponse, 'clusterStatus'>> =>\n\tr.clusterStatus !== undefined && Object.keys(r.clusterStatus).length > 0;","tryCatchPattern":"try {\n\tconst clusterStatus = await fetchAppsStatusFromCluster();\n\tresponse.clusterStatus = clusterStatus?.[appId]; // optional enrichment\n} catch {\n\t// degrade gracefully: serve local status only, log for observability\n}","preventionTips":["Treat clusterStatus as optional in every consumer - absence is a valid degraded state","Monitor instance-registry/broker health so degraded status responses are rare and visible","Retry status queries after instance rollouts complete rather than during restarts"],"tags":["apps-engine","cluster","microservices","console-warn","internal-rpc","status-endpoint"],"backgroundTag":"cluster-status-unavailable","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}