remotion-dev/remotion · error · Error

Failed to fetch ${src} (HTTP code: ${res.status})

Error message

Failed to fetch ${src} (HTTP code: ${res.status})

What it means

fetchReadWholeAsText fetches the URL, then checks res.ok; a non-2xx response throws 'Failed to fetch <src> (HTTP code: <status>)'. This is the text-resource analog of the binary 1515 check, used when pulling playlist/manifest text in full.

Source

Thrown at packages/media-parser/src/readers/from-fetch.ts:323

	}

	makeFetchRequestOrGetCached({
		range,
		src,
		controller: null,
		logLevel,
		prefetchCache,
	});
};

export const fetchReadWholeAsText: ReadWholeAsText = async (src) => {
	if (typeof src !== 'string' && src instanceof URL === false) {
		throw new Error('src must be a string when using `fetchReader`');
	}

	const res = await fetch(src);
	if (!res.ok) {
		throw new Error(`Failed to fetch ${src} (HTTP code: ${res.status})`);
	}

	return res.text();
};

export const fetchCreateAdjacentFileSource: CreateAdjacentFileSource = (
	relativePath,
	src,
) => {
	if (typeof src !== 'string' && src instanceof URL === false) {
		throw new Error('src must be a string or URL when using `fetchReader`');
	}

	return new URL(relativePath, src).toString();
};

export const fetchReader: MediaParserReaderInterface = {
	read: fetchReadContent,

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. curl the playlist URL to confirm it returns 200: `curl -I <playlist-url>`.
  2. Fix expired/forbidden URLs (refresh presigned, correct path, add auth/CORS).
  3. Verify relative URI resolution in the master playlist (the parser resolves adjacent sources via createAdjacentFileSource).
  4. Retry transient 5xx and surface a clear 'playlist unavailable' message.

Example fix

// before
await parseMedia({src: 'https://cdn/expired/playlist.m3u8', fields: {durationInSeconds: true}});

// after
const playlistUrl = await getFreshPlaylistUrl();
try {
  await parseMedia({src: playlistUrl, fields: {durationInSeconds: true}});
} catch (e) {
  if (/Failed to fetch.*HTTP code/.test(e.message)) throw new Error('Playlist unavailable');
  throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// Verify the playlist URL returns 200 before parsing
const head = await fetch(playlistUrl, {method: 'HEAD'});
if (!head.ok) throw new Error(`Playlist returned ${head.status}`);

Try / catch

try {
  await parseMedia({src: playlistUrl, fields: {durationInSeconds: true}});
} catch (e) {
  if (e instanceof Error && /Failed to fetch.*HTTP code/.test(e.message)) {
    throw new Error(`Playlist unavailable: ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Fetching an HLS playlist or other text resource referenced by the media that returns non-2xx (404 playlist URL, 403 forbidden manifest, 5xx on origin). Triggered internally when the parser resolves a .m3u8 or adjacent text file via fetchReader.readWholeAsText.

Common situations: Broken/expired playlist URLs, CDN origin errors on manifest fetch, hotlink protection, CORS blocking, or relative playlist URIs that resolve to a 404.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/6082e64b2a3ed136. Report an issue: GitHub.