remotion-dev/remotion · error · Error
Only HTTP(S) URLs can be imported
Error message
Only HTTP(S) URLs can be imported
What it means
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.
Source
Thrown at packages/browser-studio/src/download-remote-asset.ts:38
? contents.byteLength
: contents.sizeInBytes;
};
export const downloadRemoteAssetInBrowserStudio = async ({
getProject,
request,
writeStaticFile,
}: {
getProject: () => VirtualProject;
request: DownloadRemoteAssetRequest;
writeStaticFile: (request: {
contents: string | ArrayBuffer;
filePath: string;
}) => Promise<void>;
}): Promise<DownloadRemoteAssetResponse> => {
const url = new URL(request.url);
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
throw new Error('Only HTTP(S) URLs can be imported');
}
if (url.username !== '' || url.password !== '') {
throw new Error('Remote asset URLs cannot include credentials');
}
const abortController = new AbortController();
const timeout = setTimeout(() => {
abortController.abort();
}, remoteAssetDownloadTimeout);
let contents: Uint8Array;
try {
let response: Response;
try {
response = await fetch(url, {
headers: {accept: remoteAssetAcceptHeader},
signal: abortController.signal,View on GitHub (pinned to 10db9de073)
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
Example fix
// before
await operations.downloadRemoteAsset({url: pastedText}); // may be data: or blob:
// after
const parsed = new URL(pastedText);
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
throw new Error('Paste a direct http(s) link to an image');
}
await operations.downloadRemoteAsset({url: parsed.toString()}); Defensive patterns
Strategy: validation
Validate before calling
const isImportableHttpUrl = (input: string): boolean => {
try {
const u = new URL(input);
return u.protocol === 'http:' || u.protocol === 'https:';
} catch {
return false;
}
};
if (!isImportableHttpUrl(url)) throw new Error('Only http(s) links can be imported');
await operations.downloadRemoteAsset({url}); Type guard
const parseImportableUrl = (input: string): URL | null => {
try {
const u = new URL(input);
return u.protocol === 'http:' || u.protocol === 'https:' ? u : null;
} catch {
return null;
}
}; Try / catch
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; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Remote asset URLs cannot include credentials
- Remote asset exceeds the 50MB size limit
- Invalid public file path: ${path}
- The public directory was specified as "${p}", which is the r
- "cloudRunUrl" parameter must be a string, but is ${JSON.stri
AI-assisted analysis of remotion-dev/remotion@10db9de073 (2026-08-22).
Data as JSON: /api/errors/db566897b546abb8.
Report an issue: GitHub.