{"record":{"id":"db566897b546abb8","repo":"remotion-dev/remotion","slug":"only-http-s-urls-can-be-imported","errorCode":null,"errorMessage":"Only HTTP(S) URLs can be imported","messagePattern":"Only HTTP\\(S\\) URLs can be imported","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser-studio/src/download-remote-asset.ts","lineNumber":38,"sourceCode":"\t\t? contents.byteLength\n\t\t: contents.sizeInBytes;\n};\n\nexport const downloadRemoteAssetInBrowserStudio = async ({\n\tgetProject,\n\trequest,\n\twriteStaticFile,\n}: {\n\tgetProject: () => VirtualProject;\n\trequest: DownloadRemoteAssetRequest;\n\twriteStaticFile: (request: {\n\t\tcontents: string | ArrayBuffer;\n\t\tfilePath: string;\n\t}) => Promise<void>;\n}): Promise<DownloadRemoteAssetResponse> => {\n\tconst url = new URL(request.url);\n\tif (url.protocol !== 'http:' && url.protocol !== 'https:') {\n\t\tthrow new Error('Only HTTP(S) URLs can be imported');\n\t}\n\n\tif (url.username !== '' || url.password !== '') {\n\t\tthrow new Error('Remote asset URLs cannot include credentials');\n\t}\n\n\tconst abortController = new AbortController();\n\tconst timeout = setTimeout(() => {\n\t\tabortController.abort();\n\t}, remoteAssetDownloadTimeout);\n\n\tlet contents: Uint8Array;\n\ttry {\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(url, {\n\t\t\t\theaders: {accept: remoteAssetAcceptHeader},\n\t\t\t\tsignal: abortController.signal,","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/remotion-dev/remotion/blob/10db9de07356446fb0edb3c3ae211369b693d18b/packages/browser-studio/src/download-remote-asset.ts#L20-L56","documentation":"Thrown by downloadRemoteAsset in @remotion/browser-studio before any network activity when the URL to import has a protocol other than http: or https:. The importer only fetches remote assets over HTTP(S); data:, blob:, file:, and other schemes are rejected up front as a safety boundary. The promise rejects — this operation does not return an error envelope.","triggerScenarios":"Calling `downloadRemoteAsset({url})` with a `data:image/png;base64,...` URI, a `blob:` URL from the page, `file:` path, or any scheme the URL parser keeps intact. `new URL()` itself throws for truly malformed input, which surfaces as a different error.","commonSituations":"Paste handler accepting whatever is in the clipboard; drag-and-drop of files that yields blob: URLs; users pasting local file paths; frontend building URLs from unvalidated user text.","solutions":["Validate the protocol before calling downloadRemoteAsset and reject non-http(s) input in the UI","Convert data: URIs to files and write them via writeStaticFile instead of importing by URL","For blob: URLs, read the underlying Blob and write it directly","Show a clear message that only http(s) links can be imported"],"exampleFix":"// before\nawait operations.downloadRemoteAsset({url: pastedText}); // may be data: or blob:\n\n// after\nconst parsed = new URL(pastedText);\nif (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n  throw new Error('Paste a direct http(s) link to an image');\n}\nawait operations.downloadRemoteAsset({url: parsed.toString()});","handlingStrategy":"validation","validationCode":"const isImportableHttpUrl = (input: string): boolean => {\n  try {\n    const u = new URL(input);\n    return u.protocol === 'http:' || u.protocol === 'https:';\n  } catch {\n    return false;\n  }\n};\nif (!isImportableHttpUrl(url)) throw new Error('Only http(s) links can be imported');\nawait operations.downloadRemoteAsset({url});","typeGuard":"const parseImportableUrl = (input: string): URL | null => {\n  try {\n    const u = new URL(input);\n    return u.protocol === 'http:' || u.protocol === 'https:' ? u : null;\n  } catch {\n    return null;\n  }\n};","tryCatchPattern":"try { await operations.downloadRemoteAsset({url}); } catch (error) { if (error instanceof Error && error.message === 'Only HTTP(S) URLs can be imported') {/* reject input in UI */} else throw error; }","preventionTips":["Validate protocol at the input field, not just before the call","Handle dropped files and pasted data:/blob: URIs via the static-file write path instead of URL import"],"tags":["url","validation","asset-import","security","browser-studio"],"backgroundTag":"unsupported-url-scheme","analyzedSha":"10db9de07356446fb0edb3c3ae211369b693d18b","analyzedAt":"2026-08-22T21:45:17.748Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}