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
- curl the playlist URL to confirm it returns 200: `curl -I <playlist-url>`.
- Fix expired/forbidden URLs (refresh presigned, correct path, add auth/CORS).
- Verify relative URI resolution in the master playlist (the parser resolves adjacent sources via createAdjacentFileSource).
- 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
- Validate playlist/manifest URLs with curl -I before parsing.
- Keep presigned playlist URLs fresh.
- Ensure CORS and auth for playlist fetches.
- Verify relative URI resolution in master playlists.
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
- Server returned status code ${res.status} for ${resolvedUrl}
- No moov box found in header segment
- Unexpected end of file
- No moov box found
- Cannot read media ${src} without a content length. This is c
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/6082e64b2a3ed136.
Report an issue: GitHub.