RocketChat/Rocket.Chat · error · Error

App metadata download failed

Error message

App metadata download failed

What it means

Thrown during marketplace app install when the parallel call to fetch app metadata from v1/apps/{appId}?appVersion={version} rejects. The original error is preserved as cause (new Error('App metadata download failed', { cause })). Because it runs alongside the package download in Promise.all, a metadata-fetch failure prevents install even if the zip downloaded fine.

Source

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

									.fetch(`v2/apps/${this.bodyParams.appId}/download/${this.bodyParams.version}?token=${downloadToken}`, {
										headers,
										// SECURITY: user needs specific privileges to send this. Bypassing the SSRF check is okay for now.
										ignoreSsrfValidation: true,
									})
									.catch((cause) => {
										throw new Error('App package download failed', { cause });
									}),
								Apps.getMarketplaceClient()
									.fetch(`v1/apps/${this.bodyParams.appId}?appVersion=${this.bodyParams.version}`, {
										headers: {
											Authorization: `Bearer ${marketplaceToken}`,
											...headers,
										},
										// SECURITY: user needs specific privileges to send this. Bypassing the SSRF check is okay for now.
										ignoreSsrfValidation: true,
									})
									.catch((cause) => {
										throw new Error('App metadata download failed', { cause });
									}),
							]);

							if (downloadResponse.headers.get('content-type') !== 'application/zip') {
								throw new Error('Invalid url. It doesn\'t exist or is not "application/zip".');
							}

							buff = Buffer.from(await downloadResponse.arrayBuffer());
							marketplaceInfo = await marketplaceResponse.json();

							// Note: marketplace responds with an array of the marketplace info on the app, but it is expected
							// to always have one element since we are fetching a specific app version.
							if (!Array.isArray(marketplaceInfo) || marketplaceInfo?.length !== 1) {
								orchestrator.getRocketChatLogger().error({ msg: 'Error getting app information from marketplace', marketplaceInfo });
								throw new Error('Invalid response from the Marketplace');
							}

							permissionsGranted = this.bodyParams.permissionsGranted;

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Re-register the workspace with Rocket.Chat Cloud (Connectivity Services) to refresh the Bearer token.
  2. Retry the install request to rule out a transient metadata-endpoint failure.
  3. Confirm the appId/version are valid on the marketplace UI.
  4. Check server logs: the cause object on the thrown error carries the marketplace's actual HTTP status/message.
Defensive patterns

Strategy: try-catch

Validate before calling

async function hasValidWorkspaceToken(): Promise<boolean> {
  const token = await getWorkspaceAccessToken();
  return typeof token === 'string' && token.length > 0;
}

if (!await hasValidWorkspaceToken()) {
  throw new Error('Workspace not registered; metadata download will fail');
}

Type guard

const hasCause = (e: unknown): e is Error & { cause: unknown } =>
  e instanceof Error && 'cause' in e;

Try / catch

try {
  await installMarketplaceApp(appId, version);
} catch (e) {
  if (e instanceof Error && e.message === 'App metadata download failed') {
    // cause is the original marketplace fetch error
    const cause = (e as Error & { cause?: Error }).cause;
    if (cause && /401|403/.test(cause.message)) reRegisterWorkspace();
    else retryWithBackoff();
  }
}

Prevention

When it happens

Trigger: POST /api/v1/apps with marketplace install where the metadata endpoint is unreachable or returns an error, while the package download may or may not succeed. The marketplaceToken (Bearer) is attached, so an expired registration token commonly triggers this.

Common situations: Workspace token expired or revoked between the download-token call and this fetch; marketplace partial outage affecting only the metadata endpoint; appId/version mismatch where metadata does not exist but the zip does; network proxy intermittently dropping one of the two parallel requests.

Related errors


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