RocketChat/Rocket.Chat · error · Error

Invalid response from API

Error message

Invalid response from API

What it means

Thrown by AppClientOrchestrator.getInstalledApps after a GET /apps/installed?includeClusterStatus=true whose response body does not contain an `apps` key. The method uses a runtime structural check ('apps' in result) because the SDK typing cannot guarantee the shape; a missing key means the server returned something unexpected (an error object, an empty 200, or a different schema version).

Source

Thrown at apps/meteor/client/apps/orchestrator.ts:56

	}

	public handleError(error: unknown): void {
		if (hasAtLeastOnePermission(['manage-apps'])) {
			dispatchToastMessage({
				type: 'error',
				message: error,
			});
		}
	}

	public async getInstalledApps(): Promise<App[]> {
		const result = await sdk.rest.get<'/apps/installed'>('/apps/installed', { includeClusterStatus: 'true' });

		if ('apps' in result) {
			// TODO: chapter day: multiple results are returned, but we only need one
			return result.apps as App[];
		}
		throw new Error('Invalid response from API');
	}

	public async getAppsFromMarketplace(isAdminUser?: boolean): Promise<{ apps: App[]; error?: unknown }> {
		let result: App[] = [];
		try {
			result = await sdk.rest.get('/apps/marketplace', { isAdminUser: isAdminUser ? isAdminUser.toString() : 'false' });
		} catch (e) {
			if (isErrorObject(e)) {
				return { apps: [], error: e.error };
			}
			if (typeof e === 'string') {
				return { apps: [], error: e };
			}
		}

		if (!Array.isArray(result)) {
			// TODO: chapter day: multiple results are returned, but we only need one
			return { apps: [], error: 'Invalid response from API' };

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Open DevTools Network and inspect the raw /apps/installed response body — a missing `apps` key is the defect to fix.
  2. Confirm the Apps subsystem is enabled on the server (Administration > Apps) and that the user has 'manage-apps' permission.
  3. Verify server and client versions are compatible; a much older server may not return the expected envelope.
  4. If a proxy is in front, ensure it does not rewrite 200 responses for the /apps/ path.
  5. Report the actual returned shape to harden the structural check or update the rest-typings contract.
Defensive patterns

Strategy: type-guard

Type guard

function hasAppsKey(r: unknown): r is { apps: App[] } {
  return typeof r === 'object' && r !== null && 'apps' in r;
}

Try / catch

try {
  const apps = await orchestrator.getInstalledApps();
} catch (e) {
  if ((e as Error).message === 'Invalid response from API') {
    // inspect network response; likely apps-engine disabled or version mismatch
  }
}

Prevention

When it happens

Trigger: The marketplace/apps engine is disabled on the server so /apps/installed returns a non-standard body; the server returned an error envelope (e.g. { error: '...' }) that still resolved with HTTP 200; an older/newer server version where the response key differs; the request was intercepted by a proxy that replaced the body.

Common situations: Apps-engine not enabled in deployment; version mismatch between client bundle and server (e.g. client newer than server); a gateway/auth layer returning a JSON error page with 200 status; the apps-engine microservice migration producing a transitional response shape.

Related errors


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