{"record":{"id":"6082e64b2a3ed136","repo":"remotion-dev/remotion","slug":"failed-to-fetch-src-http-code-res-status","errorCode":null,"errorMessage":"Failed to fetch ${src} (HTTP code: ${res.status})","messagePattern":"Failed to fetch (.+?) \\(HTTP code: (.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/readers/from-fetch.ts","lineNumber":323,"sourceCode":"\t}\n\n\tmakeFetchRequestOrGetCached({\n\t\trange,\n\t\tsrc,\n\t\tcontroller: null,\n\t\tlogLevel,\n\t\tprefetchCache,\n\t});\n};\n\nexport const fetchReadWholeAsText: ReadWholeAsText = async (src) => {\n\tif (typeof src !== 'string' && src instanceof URL === false) {\n\t\tthrow new Error('src must be a string when using `fetchReader`');\n\t}\n\n\tconst res = await fetch(src);\n\tif (!res.ok) {\n\t\tthrow new Error(`Failed to fetch ${src} (HTTP code: ${res.status})`);\n\t}\n\n\treturn res.text();\n};\n\nexport const fetchCreateAdjacentFileSource: CreateAdjacentFileSource = (\n\trelativePath,\n\tsrc,\n) => {\n\tif (typeof src !== 'string' && src instanceof URL === false) {\n\t\tthrow new Error('src must be a string or URL when using `fetchReader`');\n\t}\n\n\treturn new URL(relativePath, src).toString();\n};\n\nexport const fetchReader: MediaParserReaderInterface = {\n\tread: fetchReadContent,","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/readers/from-fetch.ts#L305-L341","documentation":"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.","triggerScenarios":"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.","commonSituations":"Broken/expired playlist URLs, CDN origin errors on manifest fetch, hotlink protection, CORS blocking, or relative playlist URIs that resolve to a 404.","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."],"exampleFix":"// before\nawait parseMedia({src: 'https://cdn/expired/playlist.m3u8', fields: {durationInSeconds: true}});\n\n// after\nconst playlistUrl = await getFreshPlaylistUrl();\ntry {\n  await parseMedia({src: playlistUrl, fields: {durationInSeconds: true}});\n} catch (e) {\n  if (/Failed to fetch.*HTTP code/.test(e.message)) throw new Error('Playlist unavailable');\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// Verify the playlist URL returns 200 before parsing\nconst head = await fetch(playlistUrl, {method: 'HEAD'});\nif (!head.ok) throw new Error(`Playlist returned ${head.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  await parseMedia({src: playlistUrl, fields: {durationInSeconds: true}});\n} catch (e) {\n  if (e instanceof Error && /Failed to fetch.*HTTP code/.test(e.message)) {\n    throw new Error(`Playlist unavailable: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["network","http-status","hls","playlist","media-parser"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}