remotion-dev/remotion · error · Error
Could not download remote asset: ${response.status}
Error message
Could not download remote asset: ${response.status} What it means
Thrown by downloadRemoteAsset in @remotion/browser-studio when the fetch completed but `response.ok` is false — the server answered with an HTTP error status (404, 403, 500, ...). The status code is included in the message. The promise rejects directly, so callers must catch it.
Source
Thrown at packages/browser-studio/src/download-remote-asset.ts:71
try {
response = await fetch(url, {
headers: {accept: remoteAssetAcceptHeader},
signal: abortController.signal,
});
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new Error('Timed out downloading remote asset');
}
throw new Error(
`Could not fetch remote asset. The URL may not allow cross-origin requests (CORS): ${
error instanceof Error ? error.message : String(error)
}`,
);
}
if (!response.ok) {
throw new Error(`Could not download remote asset: ${response.status}`);
}
const contentLength = response.headers.get('content-length');
if (contentLength !== null && Number(contentLength) > maxRemoteAssetSize) {
abortController.abort();
throw new Error('Remote asset exceeds the 50MB size limit');
}
if (!response.body) {
const buffer = await response.arrayBuffer();
if (buffer.byteLength > maxRemoteAssetSize) {
throw new Error('Remote asset exceeds the 50MB size limit');
}
contents = new Uint8Array(buffer);
} else {
const reader = response.body.getReader();
const chunks: Uint8Array[] = [];View on GitHub (pinned to 10db9de073)
Solutions
- Open the URL directly in a browser tab and confirm it returns the image with a 200
- For 403/410 on signed URLs, generate a fresh signed URL and retry
- For 404, fix the path — the asset moved or was deleted
- For 5xx/429, wait and retry later or mirror the asset to a reliable host
Example fix
// before
await operations.downloadRemoteAsset({url}); // rejects: Could not download remote asset: 404
// after
try {
await operations.downloadRemoteAsset({url});
} catch (e) {
const m = e instanceof Error && e.message.match(/Could not download remote asset: (\d+)/);
if (m) {
const status = Number(m[1]);
if (status === 404) throw new Error('That link no longer exists — check the URL');
if (status === 403) throw new Error('The host denied access — the link may have expired');
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
const check = await fetch(url, {method: 'HEAD'});
if (!check.ok) throw new Error(`Asset URL returned ${check.status}`); Try / catch
try {
await operations.downloadRemoteAsset({url});
} catch (error) {
const m = error instanceof Error ? error.message.match(/Could not download remote asset: (\d+)/) : null;
if (m) {
const status = Number(m[1]);
if (status === 404 || status === 410) throw new Error('Link is dead — the asset was moved or deleted');
if (status === 403) throw new Error('Access denied — the link may be expired or signed incorrectly');
throw new Error(`Origin server error (${status}) — try again later`);
}
throw error;
} Prevention
- Validate pasted links with a HEAD request before adding them to a project
- Regenerate signed URLs at import time rather than persisting them
- For 5xx/429 responses, back off before retrying
When it happens
Trigger: Calling `downloadRemoteAsset({url})` for a deleted/expired link (404), a signed URL past its expiry or with a bad signature (403), a rate-limited or broken origin (429/5xx), or a URL that returns HTML error pages instead of an image.
Common situations: Pasted links from expiring share URLs; hotlink-protected hosts; CDN URLs that require a token; typos in paths.
Related errors
- Timed out downloading remote asset
- Could not fetch remote asset. The URL may not allow cross-or
- Server returned status code ${res.status} for ${resolvedUrl}
- Failed to fetch ${src} (HTTP code: ${res.status})
- Only HTTP(S) URLs can be imported
AI-assisted analysis of remotion-dev/remotion@10db9de073 (2026-08-22).
Data as JSON: /api/errors/c5fe5ba8ec3f698f.
Report an issue: GitHub.