{"record":{"id":"b58556e1283ea6e3","repo":"remotion-dev/remotion","slug":"getvideometadata-is-only-available-in-the-browse","errorCode":null,"errorMessage":"getVideoMetadata() is only available in the browser.","messagePattern":"getVideoMetadata\\(\\) is only available in the browser\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-utils/src/get-video-metadata.ts","lineNumber":17,"sourceCode":"/* eslint-disable @typescript-eslint/no-use-before-define */\nimport {isRemoteAsset} from './is-remote-asset';\nimport {onMediaError} from './media-tag-error-handling';\nimport {pLimit} from './p-limit';\nimport type {VideoMetadata} from './types';\n\nconst cache: {[key: string]: VideoMetadata} = {};\n\nconst limit = pLimit(3);\n\nconst fn = (src: string): Promise<VideoMetadata> => {\n\tif (cache[src]) {\n\t\treturn Promise.resolve(cache[src]);\n\t}\n\n\tif (typeof document === 'undefined') {\n\t\tthrow new Error('getVideoMetadata() is only available in the browser.');\n\t}\n\n\tconst video = document.createElement('video');\n\tvideo.src = src;\n\treturn new Promise<VideoMetadata>((resolve, reject) => {\n\t\tconst onError = () => {\n\t\t\tonMediaError({\n\t\t\t\terror: video.error!,\n\t\t\t\tsrc,\n\t\t\t\tcleanup,\n\t\t\t\treject,\n\t\t\t\tapi: 'getVideoMetadata()',\n\t\t\t});\n\t\t};\n\n\t\tconst onLoadedMetadata = () => {\n\t\t\tconst pixels = video.videoHeight * video.videoWidth;\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-utils/src/get-video-metadata.ts#L1-L35","documentation":"Thrown by getVideoMetadata() when `document` is undefined (line 17). The implementation builds a <video> element via document.createElement and reads loadedmetadata/duration, so it cannot run outside a browser DOM.","triggerScenarios":"Calling getVideoMetadata() in SSR, in Node scripts, in Node test runners without a DOM polyfill, or in worker/edge runtimes where document is not defined.","commonSituations":"Pre-rendering a video gallery server-side; Next.js server component fetching video metadata; CI/build-time asset validation; importing the helper into a build script that runs under Node.","solutions":["Call getVideoMetadata() only from Remotion components or other browser code paths.","For server-side metadata, use Mediabunny's metadata API or ffprobe, which do not require a DOM.","In tests, run under jsdom/happy-dom or use the Remotion browser testbed; do not invoke under plain Node.","Guard with typeof document !== 'undefined' before calling during any isomorphic code path."],"exampleFix":"// before (server call throws)\nimport {getVideoMetadata} from '@remotion/media-utils';\nconst meta = await getVideoMetadata('/clip.mp4');\n\n// after (client-side via a component effect)\nimport {getVideoMetadata} from '@remotion/media-utils';\nuseEffect(() => {\n  if (typeof document === 'undefined') return;\n  getVideoMetadata(staticFile('clip.mp4')).then(setMeta);\n}, []);","handlingStrategy":"validation","validationCode":"import {getVideoMetadata} from '@remotion/media-utils';\n\nasync function safeGetVideoMetadata(src: string) {\n  if (typeof document === 'undefined') {\n    return null; // caller should fall back to ffprobe / Mediabunny metadata\n  }\n  return getVideoMetadata(src);\n}","typeGuard":"const canUseDomVideo = (): boolean => typeof document !== 'undefined';","tryCatchPattern":"try {\n  const meta = await getVideoMetadata(src);\n} catch (err) {\n  if ((err as Error).message.includes('only available in the browser')) {\n    // server path: use ffprobe / Mediabunny\n  } else {\n    throw err;\n  }\n}","preventionTips":["Call getVideoMetadata only from Remotion client components.","For server-side metadata use ffprobe or Mediabunny's metadata API.","Guard any isomorphic call site with typeof document !== 'undefined'.","Do not run this in build scripts or serverless functions that lack a DOM."],"tags":["browser-only","ssr","dom","video","environment"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}