{"record":{"id":"a07057834c20346b","repo":"remotion-dev/remotion","slug":"failed-to-read-from-src-error-message-does","errorCode":null,"errorMessage":"Failed to read from ${src}: ${error.message}. Does the resource support CORS?","messagePattern":"Failed to read from (.+?): (.+?)\\. Does the resource support CORS\\?","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/media-utils/src/fetch-with-cors-catch.ts","lineNumber":19,"sourceCode":"export const fetchWithCorsCatch = async (src: string, init?: RequestInit) => {\n\ttry {\n\t\tconst response = await fetch(src, {\n\t\t\tmode: 'cors',\n\t\t\treferrerPolicy: 'no-referrer-when-downgrade',\n\t\t\t...init,\n\t\t});\n\t\treturn response;\n\t} catch (err) {\n\t\tconst error = err as Error;\n\t\tif (\n\t\t\t// Chrome\n\t\t\terror.message.includes('Failed to fetch') ||\n\t\t\t// Safari\n\t\t\terror.message.includes('Load failed') ||\n\t\t\t// Firefox\n\t\t\terror.message.includes('NetworkError when attempting to fetch resource')\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`Failed to read from ${src}: ${error.message}. Does the resource support CORS?`,\n\t\t\t);\n\t\t}\n\n\t\tthrow err;\n\t}\n};\n","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-utils/src/fetch-with-cors-catch.ts#L1-L27","documentation":"Thrown by fetchWithCorsCatch when the underlying fetch fails with a browser-specific cross-origin/CORS-style message ('Failed to fetch' on Chrome, 'Load failed' on Safari, 'NetworkError when attempting to fetch resource' on Firefox). The wrapper re-wraps these opaque messages into a TypeError that explicitly names the src and asks whether CORS is supported, since the original error reveals nothing about cross-origin policy.","triggerScenarios":"Fetching a media resource whose server does not return Access-Control-Allow-Origin matching the page origin, or where the resource is unreachable (DNS, offline, mixed content). The browser masks the reason as a generic network failure, which this wrapper recognizes and attributes to CORS.","commonSituations":"Loading remote media from a CDN/bucket without CORS headers. Switching from http to https (mixed content). Self-hosted media server without permissive CORS. Local dev hitting a different-origin asset without proxying.","solutions":["Configure the media origin to send Access-Control-Allow-Origin: * (or your page origin) and allow the relevant methods/headers.","If you cannot change the origin, proxy the request through your own same-origin server or use a CORS proxy.","Confirm the URL is reachable and same-scheme (avoid https page loading http media)."],"exampleFix":"// before - serving media without CORS\n// Origin: https://app.example.com loads https://cdn.example.com/video.mp4\n\n// after - cdn response headers\nAccess-Control-Allow-Origin: *","handlingStrategy":"try-catch","validationCode":"// Probe CORS support with a HEAD before the real fetch\nasync function corsOk(url: string): Promise<boolean> {\n  try { const r = await fetch(url, { method: 'HEAD', mode: 'cors' }); return r.ok || r.type === 'cors'; } catch { return false; }\n}\nawait corsOk(src);","typeGuard":null,"tryCatchPattern":"try { return await fetchWithCorsCatch(src, init); } catch (e) { if (/Does the resource support CORS/.test(String((e as Error).message))) { return await fetchWithCorsCatch(proxyUrl(src), init); } throw e; }","preventionTips":["Configure the media origin to send Access-Control-Allow-Origin.","Proxy cross-origin media through your own server when you cannot set CORS headers.","Avoid mixed-content (https page, http media)."],"tags":["media-utils","fetch","cors","network","cross-origin"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}