remotion-dev/remotion · error · Error

Could not fetch remote asset. The URL may not allow cross-or

Error message

Could not fetch remote asset. The URL may not allow cross-origin requests (CORS): ${error instanceof Error ? error.message : String(error)}

What it means

Thrown by downloadRemoteAsset in @remotion/browser-studio when the underlying fetch throws for a non-timeout reason. In a browser this is most often a CORS failure — the asset host did not send Access-Control-Allow-Origin for your page's origin — but it also covers DNS failures, refused connections, and offline errors, which is why the raw browser message is appended. The promise rejects directly.

Source

Thrown at packages/browser-studio/src/download-remote-asset.ts:63

	const abortController = new AbortController();
	const timeout = setTimeout(() => {
		abortController.abort();
	}, remoteAssetDownloadTimeout);

	let contents: Uint8Array;
	try {
		let response: Response;
		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();

View on GitHub (pinned to 10db9de073)

Solutions

  1. Verify the URL returns the image when opened directly in a tab, then confirm the host sends `Access-Control-Allow-Origin` for your origin (curl -I and look for the header)
  2. Serve the asset from a CORS-enabled host or your own CDN/proxy that adds the header
  3. If the asset is already reachable elsewhere, download it and add via writeStaticFile instead
  4. Catch the rejection and show the user that the site does not permit cross-origin imports

Example fix

// before
await operations.downloadRemoteAsset({url}); // rejects: ...may not allow cross-origin requests (CORS)

// after
try {
  await operations.downloadRemoteAsset({url});
} catch (e) {
  if (e instanceof Error && e.message.includes('cross-origin')) {
    alert('That site blocks cross-origin downloads. Save the image and upload it instead.');
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await operations.downloadRemoteAsset({url});
} catch (error) {
  if (error instanceof Error && error.message.includes('cross-origin requests (CORS)')) {
    showUserMessage('That site does not allow cross-origin downloads. Save the image and upload it instead.');
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling `downloadRemoteAsset({url})` where the host lacks CORS headers for the Studio's origin; mixed-content (https page importing http:// asset); DNS does not resolve; browser offline. The fetch fails before a Response exists, distinguishing it from HTTP status errors.

Common situations: Pasting image links from random sites (most don't allow cross-origin fetch); importing from internal hostnames not reachable from the user's machine; http:// URLs inside an https:// embedded Studio.

Related errors


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