vercel/ai · error · DownloadError

Failed to download ${url}: ${cause}

Error message

Failed to download ${url}: ${cause}

What it means

downloadBlob wraps any unexpected failure during the download — network errors, DNS failures, TLS errors, aborts, or exceeding the maxBytes size limit — in a DownloadError with the original error attached as cause. This guarantees callers always receive a DownloadError while preserving the underlying reason for debugging.

Source

Thrown at packages/provider-utils/src/download-blob.ts:54

        statusCode: response.status,
        statusText: response.statusText,
      });
    }

    const data = await readResponseWithSizeLimit({
      response,
      url,
      maxBytes: options?.maxBytes ?? DEFAULT_MAX_DOWNLOAD_SIZE,
    });

    const contentType = response.headers.get('content-type') ?? undefined;
    return new Blob([data], contentType ? { type: contentType } : undefined);
  } catch (error) {
    if (DownloadError.isInstance(error)) {
      throw error;
    }

    throw new DownloadError({ url, cause: error });
  }
}

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Inspect error.cause to identify the real failure (AbortError, size-limit, DNS, TLS).
  2. Pass a higher maxBytes option if the file legitimately exceeds the default 100 MiB limit.
  3. Check network connectivity, DNS resolution, and TLS validity for the asset host.
  4. Handle AbortError distinctly if you intentionally cancel downloads via abortSignal.
  5. Retry transient network failures with backoff.

Example fix

// before: default size cap
const blob = await downloadBlob(url);

// after: allow larger files and surface the cause
try {
  const blob = await downloadBlob(url, { maxBytes: 512 * 1024 * 1024 });
} catch (e) {
  if (DownloadError.isInstance(e)) console.error('Download failed:', e.cause);
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

const head = await fetch(url, { method: 'HEAD' });
const size = Number(head.headers.get('content-length') ?? 0);
const maxBytes = 100 * 1024 * 1024; // library default
if (size > maxBytes) throw new Error(`File ${size} bytes exceeds ${maxBytes}; pass a larger maxBytes`);

Type guard

import { DownloadError } from '@ai-sdk/provider-utils';
function isDownloadError(e: unknown): e is DownloadError {
  return DownloadError.isInstance(e);
}

Try / catch

try {
  const blob = await downloadBlob(url, { maxBytes: 256 * 1024 * 1024 });
} catch (error) {
  if (DownloadError.isInstance(error)) {
    console.error('Download failed:', error.cause); // AbortError, size limit, DNS, TLS...
  }
  throw error;
}

Prevention

When it happens

Trigger: The fetch itself rejected (offline host, DNS failure, TLS certificate error, request aborted via abortSignal) or the body reader failed, e.g. the response exceeded maxBytes (default 100 MiB) or the connection dropped mid-stream.

Common situations: Downloading very large media files that exceed the 100 MiB default cap; air-gapped/DNS-blocked environments; self-signed certificates on internal asset hosts; user-triggered AbortSignal cancellations; firewalls blocking the asset host.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/43532b31b80ca16a. Report an issue: GitHub.