remotion-dev/remotion · error · Error
No 'src' attribute was passed to the
Error message
No 'src' attribute was passed to the ${tagName} element. What it means
Companion guard to 364: after confirming the media ref exists, useMediaPlayback checks that `src` is truthy and throws this if not. It exists because the playback-sync effect needs a src to compute seek times. Distinct from the timeline 'No src passed' guards because it fires in the playback effect path and names the underlying Html5 element (<Html5Audio>/<Html5Video>).
Solutions
- Provide a valid src before the media component mounts.
- Render the component conditionally: `{url && <Video src={url} />}`.
- Default the src to a real asset path so it is never undefined.
- Audit custom wrappers to ensure src is forwarded to the underlying element.
Example fix
// before
<Video src={clip?.url} />
// after
{clip?.url ? <Video src={clip.url} /> : null} Defensive patterns
Strategy: validation
Validate before calling
if (!src) {
return null;
}
return <Video src={src} />; Type guard
const isHtmlSrc = (s: unknown): s is string => typeof s === 'string' && s.length > 0;
Prevention
- Render media elements conditionally on a validated non-empty src.
- Forward src correctly through wrappers; do not drop or default it to undefined.
- For async sources, mount the component only after resolution.
When it happens
Trigger: Rendering <Audio>/<Video> in preview/Player mode with src undefined; src set to an empty string; src cleared after mount before the playback effect runs.
Common situations: Async-loaded source where the component mounts before the URL is known; optional src prop with no default; conditional playback where the source field is empty in some data rows.
Related errors
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-08-12).
Data as JSON: /api/errors/02bc0354668512db.
Report an issue: GitHub.
Appendix: source
Thrown at packages/core/src/use-media-playback.ts:194
mediaRef.current &&
mediaRef.current.playbackRate !== playbackRateToSet
) {
mediaRef.current.playbackRate = playbackRateToSet;
}
if (mediaRef.current && mediaRef.current.preservesPitch !== preservePitch) {
mediaRef.current.preservesPitch = preservePitch;
}
}, [mediaRef, playbackRate, preservePitch]);
useEffect(() => {
const tagName = mediaType === 'audio' ? '<Html5Audio>' : '<Html5Video>';
if (!mediaRef.current) {
throw new Error(`No ${mediaType} ref found`);
}
if (!src) {
throw new Error(
`No 'src' attribute was passed to the ${tagName} element.`,
);
}
const {current} = mediaRef;
const isMediaTagBufferingOrStalled = isMediaTagBuffering || isBuffering();
let pauseReason: 'not-playing' | 'buffering' | null = null;
if (!playing) {
pauseReason = 'not-playing';
} else if (playerBuffering && !isMediaTagBufferingOrStalled) {
pauseReason = 'buffering';
}
if (!current.paused && pauseReason !== null) {
playbackLogging({
logLevel,
tag: 'pause',
message: `Pausing ${current.src} because ${getPauseReason({View on GitHub (pinned to b2f4e34732)