{"record":{"id":"8cb7ad63daf4c2a0","repo":"hcengineering/platform","slug":"download-failed","errorCode":null,"errorMessage":"Download failed","messagePattern":"Download failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/setting-resources/src/components/Backup.svelte","lineNumber":142,"sourceCode":"      }\n      return `${diffHours} hours ago`\n    }\n\n    return ''\n  }\n  function getBackupFileUrl (filename: string): string {\n    return `${backupUrl}/${workspaceId}/${filename}`\n  }\n\n  async function doDownload (downloadUrl: string, filename?: string): Promise<void> {\n    const a = document.createElement('a')\n    try {\n      const response = await fetch(downloadUrl, {\n        headers: {\n          Authorization: `Bearer ${token}`\n        }\n      })\n      if (!response.ok) throw new Error('Download failed')\n      const blob = await response.blob()\n      const url = window.URL.createObjectURL(blob)\n      a.href = url\n      if (filename !== undefined) {\n        a.download = filename\n      }\n      document.body.appendChild(a)\n      a.click()\n      // Revoke later: revoking synchronously can cancel the download before the\n      // browser has finished reading the blob (more likely over plain HTTP).\n      setTimeout(() => {\n        window.URL.revokeObjectURL(url)\n      }, 30000)\n    } catch (err) {\n      console.error('Failed to download:', err)\n    } finally {\n      document.body.removeChild(a)\n    }","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/setting-resources/src/components/Backup.svelte#L124-L160","documentation":"Backup.svelte downloads a workspace backup by fetching `downloadUrl` with a Bearer token and throws 'Download failed' whenever the HTTP response is not ok (non-2xx status). It is a thin wrapper around the server's backup endpoint; any server-side rejection surfaces as this generic error since the response status/body details are discarded.","triggerScenarios":"`fetch(downloadUrl, { headers: { Authorization: Bearer <token> } })` resolves with response.ok === false — e.g. 401 expired token, 403 insufficient permissions, 404 wrong URL, or 500 server failure while generating the backup.","commonSituations":"Session token expired before a long backup download, backup endpoint version mismatch between client plugin and server, reverse proxy timeout on large workspaces, or the workspace/backup id in downloadUrl no longer exists.","solutions":["Log response.status and response body before throwing to see the real cause, then fix accordingly.","Re-authenticate / refresh the session token and retry the download.","Verify the downloadUrl matches the current server's backup endpoint and that the backup exists.","For large workspaces, increase proxy timeout or use a streaming download to avoid gateway timeouts."],"exampleFix":"// before\nconst response = await fetch(downloadUrl, {\n  headers: { Authorization: `Bearer ${token}` }\n})\nif (!response.ok) throw new Error('Download failed')\n// after\nconst response = await fetch(downloadUrl, {\n  headers: { Authorization: `Bearer ${token}` }\n})\nif (!response.ok) {\n  throw new Error(`Download failed: HTTP ${response.status} ${await response.text().catch(() => '')}`)\n}","handlingStrategy":"try-catch","validationCode":"if (!token || tokenExpiry < Date.now()) {\n  await reauthenticate()\n}\nconst head = await fetch(downloadUrl, { method: 'HEAD', headers: { Authorization: `Bearer ${token}` } })\nif (!head.ok) throw new Error(`Backup endpoint not ready: ${head.status}`)","typeGuard":"function isOk(r: Response): r is Response & { ok: true } { return r.ok }","tryCatchPattern":"try {\n  await downloadBackup()\n} catch (e) {\n  if (e.message === 'Download failed') {\n    await reauthenticate()\n    retryDownload()\n  } else throw e\n}","preventionTips":["Check token freshness before long operations","Log response.status and body for diagnostics","Keep server and backup plugin versions in sync","Raise proxy timeouts for large workspaces"],"tags":["network","http","backup","authentication"],"backgroundTag":"http-request-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}