remotion-dev/remotion · error · Error

Timed out downloading remote asset

Error message

Timed out downloading remote asset

What it means

Thrown by downloadRemoteAsset in @remotion/browser-studio when the fetch is aborted by the built-in timeout (remoteAssetDownloadTimeout via AbortController) — the asset server did not respond within the allowed window, either for the initial response or while streaming the body. The AbortError is translated to this message; the promise rejects directly.

Source

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

		throw new Error('Remote asset URLs cannot include credentials');
	}

	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');
		}

View on GitHub (pinned to 10db9de073)

Solutions

  1. Retry the import — transient timeouts often succeed on a second attempt
  2. Host the asset on a faster CDN closer to the user, or pre-compress/resize it
  3. Check the URL opens quickly in a browser tab on the same network
  4. If it consistently times out, download the asset manually and add it via writeStaticFile

Example fix

// before
await operations.downloadRemoteAsset({url}); // may reject: Timed out downloading remote asset

// after
async function importWithRetry(url: string, attempts = 2) {
  for (let i = 0; i <= attempts; i++) {
    try {
      return await operations.downloadRemoteAsset({url});
    } catch (e) {
      const isTimeout = e instanceof Error && e.message === 'Timed out downloading remote asset';
      if (!isTimeout || i === attempts) throw e;
    }
  }
  throw new Error('unreachable');
}
Defensive patterns

Strategy: retry

Validate before calling

const reachable = await fetch(url, {method: 'HEAD', signal: AbortSignal.timeout(5000)}).then((r) => r.ok).catch(() => false);
if (!reachable) throw new Error('Asset server not responding — try again later');

Try / catch

const isTimeout = (e: unknown) => e instanceof Error && e.message === 'Timed out downloading remote asset';
try {
  result = await operations.downloadRemoteAsset({url});
} catch (error) {
  if (isTimeout(error) && attempt < maxAttempts) { await backoff(attempt); return download(attempt + 1); }
  throw error;
}

Prevention

When it happens

Trigger: Importing a large image from a slow or distant server; server stalls mid-download (the body-streaming loop is also covered by the same timeout); client network degraded (offline, throttled); server takes long to generate the asset on the fly.

Common situations: Users on slow connections importing multi-megapixel images; origin servers behind slow CDN cold starts; mobile networks; localhost dev with a stalled mock server.

Understand the failure class

Related errors


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