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
- Inspect error.cause to identify the real failure (AbortError, size-limit, DNS, TLS).
- Pass a higher maxBytes option if the file legitimately exceeds the default 100 MiB limit.
- Check network connectivity, DNS resolution, and TLS validity for the asset host.
- Handle AbortError distinctly if you intentionally cancel downloads via abortSignal.
- 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
- Always read error.cause to find the real failure reason.
- Set maxBytes explicitly for known-large media files (default is 100 MiB).
- Distinguish user-initiated aborts (AbortError) from genuine network failures.
- Verify DNS/TLS reachability of asset hosts in restricted networks.
- Retry transient network errors with backoff.
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
- Failed to download ${url}: ${statusCode} ${statusText}
- Too many redirects (max ${maxRedirects})
- Error repairing tool call: ${getErrorMessage(cause)}
- Video generation timed out after ${timeoutMs}ms.
- The response body is empty.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/43532b31b80ca16a.
Report an issue: GitHub.