{"record":{"id":"2560dd3ffc874263","repo":"remotion-dev/remotion","slug":"remote-asset-is-not-a-supported-image","errorCode":null,"errorMessage":"Remote asset is not a supported image","messagePattern":"Remote asset is not a supported image","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser-studio/src/download-remote-asset.ts","lineNumber":131,"sourceCode":"\t\t\tlet offset = 0;\n\t\t\tfor (const chunk of chunks) {\n\t\t\t\tcontents.set(chunk, offset);\n\t\t\t\toffset += chunk.byteLength;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.name === 'AbortError') {\n\t\t\tthrow new Error('Timed out downloading remote asset');\n\t\t}\n\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n\n\tconst fileType = detectFileType(contents);\n\tif (!isImageFileType(fileType)) {\n\t\tthrow new Error('Remote asset is not a supported image');\n\t}\n\n\tconst assetPath = getRemoteAssetFilename({fileType, url});\n\tconst existing = Object.entries(getProject().publicFiles ?? {}).find(\n\t\t([path]) => path.replace(/^\\/+/, '') === assetPath,\n\t)?.[1];\n\tif (\n\t\texisting !== undefined &&\n\t\tgetPublicFileSize(existing) !== contents.byteLength\n\t) {\n\t\tthrow new Error(\n\t\t\t`File with name ${assetPath} already exists and is different`,\n\t\t);\n\t}\n\n\tif (existing === undefined) {\n\t\tawait writeStaticFile({\n\t\t\tcontents: contents.slice().buffer,","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/remotion-dev/remotion/blob/10db9de07356446fb0edb3c3ae211369b693d18b/packages/browser-studio/src/download-remote-asset.ts#L113-L149","documentation":"After a successful download, Browser Studio sniffs the file's magic bytes with detectFileType() and requires isImageFileType() to pass. Remote import supports only raster images - PNG, APNG, JPEG, WebP, BMP, and GIF (the same set as the accept header sent with the request). Videos, audio, PDFs, HTML pages, SVGs, AVIF, and unrecognized binaries are rejected even when the HTTP request returned 200.","triggerScenarios":"Calling downloadRemoteAssetInBrowserStudio with a URL that returns anything other than a sniffer-recognized PNG/APNG/JPEG/WebP/BMP/GIF payload: an MP4 or MOV, an HTML soft-error page served with status 200, an SVG or AVIF image, a JSON error body from a CORS relay, or a truncated/corrupt file.","commonSituations":"Pasting a link to a video instead of a still; CDN edge pages that return HTML with 200; dynamic URLs that 200 with an error document; SVG or AVIF assets that are valid images but outside the supported set.","solutions":["Verify the URL actually returns a PNG, JPEG, WebP, BMP, or GIF image (open it in a browser tab and check)","If a proxy or CORS relay wraps errors in HTML/JSON with status 200, use the direct asset URL instead","Convert SVG or AVIF assets to PNG/WebP before importing","Import video and audio through a different mechanism - remote import is image-only"],"exampleFix":"// before: importing an SVG (not in the supported set)\nawait downloadRemoteAssetInBrowserStudio({getProject, request: {url: 'https://example.com/logo.svg'}, writeStaticFile});\n\n// after: preflight the content type and convert to a supported raster format\nconst head = await fetch('https://example.com/logo.svg', {method: 'HEAD'});\nconst type = head.headers.get('content-type') ?? '';\nif (!['image/png', 'image/jpeg', 'image/webp', 'image/bmp', 'image/gif'].some((t) => type.startsWith(t))) {\n  throw new Error('Convert the asset to PNG/JPEG/WebP/BMP/GIF before remote import');\n}","handlingStrategy":"validation","validationCode":"const supported = ['image/png', 'image/jpeg', 'image/webp', 'image/bmp', 'image/gif'];\nconst head = await fetch(url, {method: 'HEAD'});\nconst contentType = (head.headers.get('content-type') ?? '').split(';')[0];\nif (!supported.some((t) => t === contentType)) {\n  throw new Error(`Remote import supports PNG/JPEG/WebP/BMP/GIF only, got ${contentType || 'unknown'}`);\n}","typeGuard":"const isSupportedImageContentType = (value: string | null): boolean =>\n  ['image/png', 'image/jpeg', 'image/webp', 'image/bmp', 'image/gif']\n    .some((t) => (value ?? '').startsWith(t));","tryCatchPattern":"try {\n  await downloadRemoteAssetInBrowserStudio({getProject, request, writeStaticFile});\n} catch (e) {\n  if (/not a supported image/.test(String((e as Error).message))) {\n    // tell the user the URL did not return PNG/APNG/JPEG/WebP/BMP/GIF bytes\n  } else throw e;\n}","preventionTips":["Preflight with a HEAD request and require an image/* content type matching the supported set","Beware URLs that return HTML error pages with status 200 - they fail the sniffer, not the fetch","Convert SVG/AVIF to PNG/WebP before offering remote import"],"tags":["browser-studio","remote-asset","file-type","image","validation"],"backgroundTag":"unsupported-file-type","analyzedSha":"10db9de07356446fb0edb3c3ae211369b693d18b","analyzedAt":"2026-08-22T21:45:17.748Z","contentChangedAt":"2026-08-22T21:45:17.748Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}