{"record":{"id":"1adee8636ef8bbc4","repo":"remotion-dev/remotion","slug":"no-mediatype-ref-found","errorCode":null,"errorMessage":"No ${mediaType} ref found","messagePattern":"No (.+?) ref found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/use-media-playback.ts","lineNumber":218,"sourceCode":"\t// and it is also in a useLayoutEffect.\n\tuseLayoutEffect(() => {\n\t\tconst playbackRateToSet = Math.max(0, playbackRate);\n\t\tif (\n\t\t\tmediaRef.current &&\n\t\t\tmediaRef.current.playbackRate !== playbackRateToSet\n\t\t) {\n\t\t\tmediaRef.current.playbackRate = playbackRateToSet;\n\t\t}\n\n\t\tif (mediaRef.current && mediaRef.current.preservesPitch !== preservePitch) {\n\t\t\tmediaRef.current.preservesPitch = preservePitch;\n\t\t}\n\t}, [mediaRef, playbackRate, preservePitch]);\n\n\tuseEffect(() => {\n\t\tconst tagName = mediaType === 'audio' ? '<Html5Audio>' : '<Html5Video>';\n\t\tif (!mediaRef.current) {\n\t\t\tthrow new Error(`No ${mediaType} ref found`);\n\t\t}\n\n\t\tif (!src) {\n\t\t\tthrow new Error(\n\t\t\t\t`No 'src' attribute was passed to the ${tagName} element.`,\n\t\t\t);\n\t\t}\n\n\t\tconst {current} = mediaRef;\n\n\t\tconst action = getMediaSyncAction({\n\t\t\tduration: current.duration,\n\t\t\tcurrentTime: current.currentTime,\n\t\t\tpaused: current.paused,\n\t\t\tended: current.ended,\n\t\t\tdesiredUnclampedTime,\n\t\t\tmediaTagTime: mediaTagCurrentTime.current.time,\n\t\t\tmediaTagLastUpdate: mediaTagCurrentTime.current.lastUpdate,","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/use-media-playback.ts#L200-L236","documentation":"Inside useMediaPlayback's main useEffect, the hook asserts mediaRef.current is set before syncing playback. A null ref means the underlying <audio>/<video> element is not mounted at effect time — usually because the JSX never actually rendered the tag (conditional render, ref attached to the wrong node, or the element was unmounted between render and commit).","triggerScenarios":"Forwarding the media ref to a node that is conditionally rendered and the condition was false; passing a ref object that is never attached; the element unmounting synchronously before the effect runs; custom Audio/Video wrappers that drop the ref.","commonSituations":"Building a custom media wrapper and forgetting to spread/forward the ref onto the underlying <video> tag; conditional rendering of the source element; SSR where the ref never attaches; refactoring that renamed the ref prop.","solutions":["Ensure the ref returned by Remotion is attached to the real <audio>/<video> DOM node and that node always mounts with the component.","If you wrap <Video>/<Audio>, use React.forwardRef and forward the ref to the underlying media element.","Remove conditional rendering that hides the media tag while the component is mounted.","Reproduce in isolation: render just <Video src={url}/> with no wrapper to confirm the wrapper is the cause."],"exampleFix":"// before\nconst MyVideo = ({src}) => {\n  return <video src={src} />; // ref dropped\n};\n\n// after\nconst MyVideo = React.forwardRef(({src}, ref) => {\n  return <video src={src} ref={ref} />;\n});","handlingStrategy":"validation","validationCode":"// Ensure the ref is attached to a always-mounted element.\n// In custom wrappers:\n// const MyVideo = React.forwardRef((props, ref) => <video ref={ref} {...props} />);","typeGuard":"const isAttached = (ref: React.RefObject<Element | null>) => ref.current instanceof HTMLMediaElement;","tryCatchPattern":null,"preventionTips":["Always forward the media ref onto the real <audio>/<video> DOM node via React.forwardRef.","Do not conditionally hide the media tag while its parent component is mounted.","Avoid detaching the ref in effects; keep the element mounted for the component's lifetime."],"tags":["remotion","media","ref","dom","use-effect"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}