{"record":{"id":"a214cab059ffb48e","repo":"RocketChat/Rocket.Chat","slug":"app-metadata-download-failed","errorCode":null,"errorMessage":"App metadata download failed","messagePattern":"App metadata download failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/apps/communication/rest.ts","lineNumber":322,"sourceCode":"\t\t\t\t\t\t\t\t\t.fetch(`v2/apps/${this.bodyParams.appId}/download/${this.bodyParams.version}?token=${downloadToken}`, {\n\t\t\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\t\t\t// SECURITY: user needs specific privileges to send this. Bypassing the SSRF check is okay for now.\n\t\t\t\t\t\t\t\t\t\tignoreSsrfValidation: true,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t.catch((cause) => {\n\t\t\t\t\t\t\t\t\t\tthrow new Error('App package download failed', { cause });\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tApps.getMarketplaceClient()\n\t\t\t\t\t\t\t\t\t.fetch(`v1/apps/${this.bodyParams.appId}?appVersion=${this.bodyParams.version}`, {\n\t\t\t\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t\t\t\tAuthorization: `Bearer ${marketplaceToken}`,\n\t\t\t\t\t\t\t\t\t\t\t...headers,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t// SECURITY: user needs specific privileges to send this. Bypassing the SSRF check is okay for now.\n\t\t\t\t\t\t\t\t\t\tignoreSsrfValidation: true,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t.catch((cause) => {\n\t\t\t\t\t\t\t\t\t\tthrow new Error('App metadata download failed', { cause });\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t]);\n\n\t\t\t\t\t\t\tif (downloadResponse.headers.get('content-type') !== 'application/zip') {\n\t\t\t\t\t\t\t\tthrow new Error('Invalid url. It doesn\\'t exist or is not \"application/zip\".');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbuff = Buffer.from(await downloadResponse.arrayBuffer());\n\t\t\t\t\t\t\tmarketplaceInfo = await marketplaceResponse.json();\n\n\t\t\t\t\t\t\t// Note: marketplace responds with an array of the marketplace info on the app, but it is expected\n\t\t\t\t\t\t\t// to always have one element since we are fetching a specific app version.\n\t\t\t\t\t\t\tif (!Array.isArray(marketplaceInfo) || marketplaceInfo?.length !== 1) {\n\t\t\t\t\t\t\t\torchestrator.getRocketChatLogger().error({ msg: 'Error getting app information from marketplace', marketplaceInfo });\n\t\t\t\t\t\t\t\tthrow new Error('Invalid response from the Marketplace');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tpermissionsGranted = this.bodyParams.permissionsGranted;","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/ee/server/apps/communication/rest.ts#L304-L340","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-register the workspace with Rocket.Chat Cloud (Connectivity Services) to refresh the Bearer token.","Retry the install request to rule out a transient metadata-endpoint failure.","Confirm the appId/version are valid on the marketplace UI.","Check server logs: the cause object on the thrown error carries the marketplace's actual HTTP status/message."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"async function hasValidWorkspaceToken(): Promise<boolean> {\n  const token = await getWorkspaceAccessToken();\n  return typeof token === 'string' && token.length > 0;\n}\n\nif (!await hasValidWorkspaceToken()) {\n  throw new Error('Workspace not registered; metadata download will fail');\n}","typeGuard":"const hasCause = (e: unknown): e is Error & { cause: unknown } =>\n  e instanceof Error && 'cause' in e;","tryCatchPattern":"try {\n  await installMarketplaceApp(appId, version);\n} catch (e) {\n  if (e instanceof Error && e.message === 'App metadata download failed') {\n    // cause is the original marketplace fetch error\n    const cause = (e as Error & { cause?: Error }).cause;\n    if (cause && /401|403/.test(cause.message)) reRegisterWorkspace();\n    else retryWithBackoff();\n  }\n}","preventionTips":["Keep workspace registration fresh (re-register if tokens are short-lived).","Retry installs with backoff for transient metadata-endpoint failures.","Inspect the preserved cause to distinguish auth vs network vs outage."],"tags":["apps-engine","marketplace","network","install"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}