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
- 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.
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
- 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
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
- response.statusText
- Failed to fetch config
- unknownError(response.statusText)
- Failed to delete file
- Failed to delete file
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/8cb7ad63daf4c2a0.
Report an issue: GitHub.