RocketChat/Rocket.Chat · error · Error

App package download failed

Error message

App package download failed

What it means

Thrown during marketplace app install (POST /apps with appId+version+marketplace) when the call to fetch the app zip from v2/apps/{appId}/download/{version} rejects. The original rejection is preserved as the cause (new Error('App package download failed', { cause })). The route runs both the package download and the metadata fetch in parallel via Promise.all, so a failure on either short-circuits.

Source

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

						} catch (err: any) {
							orchestrator.getRocketChatLogger().error({ msg: 'Error fetching App from URL:', err });
							return API.v1.internalError();
						}
					} else if ('appId' in this.bodyParams && this.bodyParams.appId && this.bodyParams.marketplace && this.bodyParams.version) {
						const headers = getDefaultHeaders();
						try {
							const downloadToken = await getWorkspaceAccessToken(true, 'marketplace:download', false);
							const marketplaceToken = await getWorkspaceAccessToken();

							const [downloadResponse, marketplaceResponse] = await Promise.all([
								Apps.getMarketplaceClient()
									.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".');
							}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Check outbound connectivity from the server to the marketplace host (verify Site_Url and proxy settings).
  2. Confirm the workspace is registered (Administration > Connectivity Services) so getWorkspaceAccessToken returns a valid download token.
  3. Retry the install; transient marketplace failures often resolve on retry.
  4. Verify the requested appId/version exist on the marketplace; an unpublished or yanked version will 404.
  5. Inspect the preserved cause in logs (the logged err includes the original fetch error) for the real HTTP status.
Defensive patterns

Strategy: try-catch

Validate before calling

async function canReachMarketplace(): Promise<boolean> {
  try {
    const res = await fetch('https://marketplace.rocket.chat/health', { method: 'GET' });
    return res.ok;
  } catch { return false; }
}

if (!await canReachMarketplace()) {
  throw new Error('Marketplace unreachable; cannot download app package');
}

Type guard

const isInstallPayload = (body: unknown): body is { appId: string; version: string; marketplace: true } =>
  typeof body === 'object' &&
  typeof (body as any)?.appId === 'string' &&
  typeof (body as any)?.version === 'string' &&
  (body as any)?.marketplace === true;

Try / catch

try {
  await installMarketplaceApp(appId, version);
} catch (e) {
  if (e instanceof Error && e.message === 'App package download failed') {
    // e.cause holds the original fetch error - inspect it
    console.error('Underlying cause:', (e as Error & { cause?: Error }).cause);
    retryWithBackoff();
  }
}

Prevention

When it happens

Trigger: POST /api/v1/apps with body { appId, version, marketplace: true } while the workspace cannot reach the marketplace, the download token is invalid/expired, the version does not exist on the marketplace, or the marketplace host returns a non-2xx/throwing response for the download URL.

Common situations: Air-gapped or proxy-restricted server without outbound access to the marketplace; expired/missing workspace registration token (getWorkspaceAccessToken for the download scope failed silently); user requested a version that was unpublished; transient marketplace outage or DNS failure.

Related errors


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