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

  1. Open the URL directly in a browser tab and confirm it returns the image with a 200
  2. For 403/410 on signed URLs, generate a fresh signed URL and retry
  3. For 404, fix the path — the asset moved or was deleted
  4. 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

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


AI-assisted analysis of remotion-dev/remotion@10db9de073 (2026-08-22). Data as JSON: /api/errors/c5fe5ba8ec3f698f. Report an issue: GitHub.