iOfficeAI/AionUi · error · Error

update.errors.downloadFailed

update.errors.downloadFailed

Error message

update.errors.downloadFailed

What it means

Thrown when downloading an update artifact fails at the HTTP level: the response status is not ok (non-2xx). The status code is interpolated into the i18n message.

Source

Thrown at packages/desktop/src/process/bridge/updateBridge.ts:523

      downloadId,
      status,
      receivedBytes,
      totalBytes,
      percent,
      bytesPerSecond,
    });
  };

  emitThrottled('starting');

  log.info('[update-download] Downloading from URL:', url);

  let stream: fs.WriteStream | null = null;
  try {
    const res = await fetchWithAllowlistedRedirects(url, abortController.signal);

    if (!res.ok) {
      throw new Error((await getI18n()).t('update.errors.downloadFailed', { status: res.status }));
    }

    const contentLengthHeader = res.headers.get('content-length');
    if (contentLengthHeader) {
      const parsed = parseInt(contentLengthHeader, 10);
      if (Number.isFinite(parsed) && parsed > 0) {
        totalBytes = parsed;
      }
    }

    if (!res.body) {
      throw new Error((await getI18n()).t('update.errors.downloadNoBody'));
    }

    stream = fs.createWriteStream(file_path);
    const reader = res.body.getReader();

    let doneReading = false;

View on GitHub (pinned to 711aa0550e)

Solutions

  1. Retry the download — transient CDN 5xx or artifact propagation delay is common right after a release
  2. Verify the artifact URL from the manifest opens directly (curl -I) and check the status code
  3. Re-fetch the manifest to get a fresh URL in case the old one was rotated
  4. If 403, check CDN auth/signature configuration and whether the download host requires headers

Example fix

// before
const res = await fetchWithAllowlistedRedirects(url, abortController.signal);
if (!res.ok) {
  throw new Error((await getI18n()).t('update.errors.downloadFailed', { status: res.status }));
}

// after (one retry for transient failures)
let res = await fetchWithAllowlistedRedirects(url, abortController.signal);
if ((res.status === 404 || res.status >= 500) && !retried) {
  retried = true;
  await new Promise((r) => setTimeout(r, 2000));
  res = await fetchWithAllowlistedRedirects(url, abortController.signal);
}
if (!res.ok) {
  throw new Error((await getI18n()).t('update.errors.downloadFailed', { status: res.status }));
}
Defensive patterns

Strategy: retry

Validate before calling

const head = await fetch(artifactUrl, { method: 'HEAD' });
if (!head.ok) { /* don't start the download; surface status */ }

Try / catch

catch (err) {
  if (err instanceof Error && err.message.includes('downloadFailed')) {
    await backoffRetry(); // one retry for 404/5xx after fresh manifest fetch
  }
  throw err;
}

Prevention

When it happens

Trigger: fetchWithAllowlistedRedirects returns 403/404/5xx for the artifact URL — e.g. the file was removed from the CDN, the URL expired (signed link), or the server errored.

Common situations: Artifact deleted/rotated on the CDN while the manifest still references it, expired pre-signed URLs, region-blocked downloads, or CDN misconfiguration. 404 after a new release rollout is typical.

Related errors


AI-assisted analysis of iOfficeAI/AionUi@711aa0550e (2026-08-28). Data as JSON: /api/errors/61267ae16a48d420. Report an issue: GitHub.