remotion-dev/remotion · error · Error
Remote asset URLs cannot include credentials
Error message
Remote asset URLs cannot include credentials
What it means
Thrown by downloadRemoteAsset in @remotion/browser-studio when the URL contains an userinfo component (`https://user:pass@host/...`) — url.username or url.password is non-empty. Credentials embedded in URLs are rejected because they would be sent to third-party hosts, logged, and persisted into the project, leaking secrets. The check happens before any fetch, and the promise rejects directly.
Source
Thrown at packages/browser-studio/src/download-remote-asset.ts:42
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,
});
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new Error('Timed out downloading remote asset');View on GitHub (pinned to 10db9de073)
Solutions
- Strip the userinfo before importing: rebuild the URL from origin + pathname + search
- Host the asset somewhere that does not require basic auth, or put the token in a supported header/query mechanism
- Catch the rejection and tell the user the link contains credentials and cannot be imported
- Audit pasted URLs in the UI before submission
Example fix
// before
await operations.downloadRemoteAsset({url: rawUrl}); // rawUrl = https://user:pass@cdn.example.com/a.png
// after
const u = new URL(rawUrl);
u.username = '';
u.password = '';
await operations.downloadRemoteAsset({url: u.toString()}); // https://cdn.example.com/a.png Defensive patterns
Strategy: validation
Validate before calling
const stripUrlCredentials = (input: string): string => {
const u = new URL(input);
u.username = '';
u.password = '';
return u.toString();
};
await operations.downloadRemoteAsset({url: stripUrlCredentials(rawUrl)}); Type guard
const hasUrlCredentials = (input: string): boolean => {
try { const u = new URL(input); return u.username !== '' || u.password !== ''; } catch { return false; }
}; Try / catch
try { await operations.downloadRemoteAsset({url}); } catch (error) { if (error instanceof Error && error.message === 'Remote asset URLs cannot include credentials') { /* ask user for a clean link */ } else throw error; } Prevention
- Normalize pasted URLs through `new URL()` and clear username/password before any use
- Never build asset URLs by concatenating credentials; use signed URLs or header-based auth where supported
When it happens
Trigger: Calling `downloadRemoteAsset({url: 'https://user:pass@example.com/img.png'})`; URLs copied from browsers/tools that preserve basic-auth userinfo; automated pipelines that embed API keys in asset URLs.
Common situations: Users pasting links from password-protected staging servers; scripts embedding CDN tokens as basic auth instead of query params or headers; copied links that silently include `user@host`.
Related errors
- Only HTTP(S) URLs can be imported
- Timed out downloading remote asset
- Could not fetch remote asset. The URL may not allow cross-or
- Could not download remote asset: ${response.status}
- Remote asset exceeds the 50MB size limit
AI-assisted analysis of remotion-dev/remotion@10db9de073 (2026-08-22).
Data as JSON: /api/errors/d1b3b7dea33f249a.
Report an issue: GitHub.