hcengineering/platform · error · Error

Download failed

Error message

Download failed

What it means

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.

Source

Thrown at plugins/setting-resources/src/components/Backup.svelte:142

      }
      return `${diffHours} hours ago`
    }

    return ''
  }
  function getBackupFileUrl (filename: string): string {
    return `${backupUrl}/${workspaceId}/${filename}`
  }

  async function doDownload (downloadUrl: string, filename?: string): Promise<void> {
    const a = document.createElement('a')
    try {
      const response = await fetch(downloadUrl, {
        headers: {
          Authorization: `Bearer ${token}`
        }
      })
      if (!response.ok) throw new Error('Download failed')
      const blob = await response.blob()
      const url = window.URL.createObjectURL(blob)
      a.href = url
      if (filename !== undefined) {
        a.download = filename
      }
      document.body.appendChild(a)
      a.click()
      // Revoke later: revoking synchronously can cancel the download before the
      // browser has finished reading the blob (more likely over plain HTTP).
      setTimeout(() => {
        window.URL.revokeObjectURL(url)
      }, 30000)
    } catch (err) {
      console.error('Failed to download:', err)
    } finally {
      document.body.removeChild(a)
    }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Log response.status and response body before throwing to see the real cause, then fix accordingly.
  2. Re-authenticate / refresh the session token and retry the download.
  3. Verify the downloadUrl matches the current server's backup endpoint and that the backup exists.
  4. For large workspaces, increase proxy timeout or use a streaming download to avoid gateway timeouts.

Example fix

// before
const response = await fetch(downloadUrl, {
  headers: { Authorization: `Bearer ${token}` }
})
if (!response.ok) throw new Error('Download failed')
// after
const response = await fetch(downloadUrl, {
  headers: { Authorization: `Bearer ${token}` }
})
if (!response.ok) {
  throw new Error(`Download failed: HTTP ${response.status} ${await response.text().catch(() => '')}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!token || tokenExpiry < Date.now()) {
  await reauthenticate()
}
const head = await fetch(downloadUrl, { method: 'HEAD', headers: { Authorization: `Bearer ${token}` } })
if (!head.ok) throw new Error(`Backup endpoint not ready: ${head.status}`)

Type guard

function isOk(r: Response): r is Response & { ok: true } { return r.ok }

Try / catch

try {
  await downloadBackup()
} catch (e) {
  if (e.message === 'Download failed') {
    await reauthenticate()
    retryDownload()
  } else throw e
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/8cb7ad63daf4c2a0. Report an issue: GitHub.