{"record":{"id":"793f0405eea8ed0f","repo":"remotion-dev/remotion","slug":"could-not-read-media-metadata-for-src","errorCode":null,"errorMessage":"Could not read media metadata for ${src}","messagePattern":"Could not read media metadata for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio/src/helpers/get-asset-metadata.ts","lineNumber":157,"sourceCode":"\n\t\t\tif (!contentLength) {\n\t\t\t\tthrow new Error('Unexpected error: content-length is null');\n\t\t\t}\n\n\t\t\tsize = Number(contentLength);\n\t\t}\n\n\t\tconst fetchedAt = Date.now();\n\t\tconst srcWithTime = addTime ? addAssetCacheBust({fetchedAt, src}) : src;\n\n\t\tconst fileType = getPreviewFileType(\n\t\t\tcanvasContent.type === 'asset' ? canvasContent.asset : src,\n\t\t);\n\n\t\tif (fileType === 'video' || fileType === 'audio') {\n\t\t\tconst mediaMetadata = await getMediaMetadata(srcWithTime);\n\t\t\tif (mediaMetadata === null) {\n\t\t\t\tthrow new Error(`Could not read media metadata for ${src}`);\n\t\t\t}\n\n\t\t\tconst width = mediaMetadata.width ?? 1920;\n\t\t\tconst height = mediaMetadata.height ?? 1080;\n\t\t\treturn {\n\t\t\t\ttype: 'found',\n\t\t\t\tsize,\n\t\t\t\tdimensions: {width, height},\n\t\t\t\tfetchedAt,\n\t\t\t\tmediaMetadata,\n\t\t\t};\n\t\t}\n\n\t\tif (fileType === 'image') {\n\t\t\tconst resolution = await new Promise<AssetMetadata>((resolve, reject) => {\n\t\t\t\tconst img = new Image();\n\t\t\t\timg.onload = () => {\n\t\t\t\t\tresolve({","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/studio/src/helpers/get-asset-metadata.ts#L139-L175","documentation":"Remotion Studio's asset metadata reader throws this when `getMediaMetadata()` returns null for a video or audio asset, meaning the browser could not load and parse the media file's metadata. The source URL is constructed from the passed `src` (or the current canvas asset) possibly with a cache-busting timestamp. A null result means the media element failed to load entirely — wrong URL, unsupported codec, CORS failure, or a missing file.","triggerScenarios":"Calling getAssetMetadata with a video/audio `src` that 404s, is blocked by CORS, points to a file outside the public folder, uses a codec the browser can't decode (e.g. certain HEVC/proprietary formats), or references a relative path that doesn't resolve to the Studio's dev server.","commonSituations":"Typos or wrong-case filenames in <Video src>/<Audio src>; assets in a public/ folder that isn't configured; absolute filesystem paths used as src; serving media from a CDN without CORS headers; broken asset imports after moving files; very large files still uploading.","solutions":["Verify the src URL resolves: open it directly in the browser and confirm the media plays","If the file lives in public/, reference it as '/filename.ext' from staticFile() and confirm the file exists with exact casing","For remote media, ensure the server sends Access-Control-Allow-Origin headers","Re-encode the file to a web-safe codec (H.264/AAC in MP4 or WebM) if the browser can't decode it","Check the Network tab for the failing media request (404, CORS error, or decode error)"],"exampleFix":"// before\n<Video src=\"/MyVid.mp4\" /> // wrong casing, 404s on case-sensitive servers\n\n// after\nimport staticFile from '@remotion/static-file';\n<Video src={staticFile('myvid.mp4')} />","handlingStrategy":"type-guard","validationCode":"// Probe the asset before relying on metadata\nconst probe = document.createElement('video');\nprobe.preload = 'metadata';\nprobe.src = src;\nawait new Promise((res) => {\n  probe.onloadedmetadata = res;\n  probe.onerror = res;\n});\nif (probe.readyState < 1) {\n  // src is unloadable; fix path/CORS/codec before calling getAssetMetadata\n}","typeGuard":"const canLoadMediaMetadata = async (src: string): Promise<boolean> => {\n  const el = document.createElement(src.match(/\\.mp4$|\\.webm$|\\.mov$/i) ? 'video' : 'audio');\n  el.preload = 'metadata';\n  el.src = src;\n  return new Promise((resolve) => {\n    el.addEventListener('loadedmetadata', () => resolve(true), {once: true});\n    el.addEventListener('error', () => resolve(false), {once: true});\n  });\n};","tryCatchPattern":"try {\n  const meta = await getAssetMetadata({src});\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Could not read media metadata for')) {\n    // fall back to placeholder dimensions and log the failing src\n  }\n  throw err;\n}","preventionTips":["Use staticFile() for public assets instead of hand-written paths","Confirm media URLs load in a plain browser tab before referencing them","Serve remote media with CORS headers","Encode media in browser-supported codecs (H.264/AAC MP4, WebM)"],"tags":["media","video","audio","metadata","cors","static-file"],"backgroundTag":"media-metadata-load-failed","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-08-28T15:39:09.316Z","contentChangedAt":"2026-08-28T15:39:09.316Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}