remotion-dev/remotion · error · TypeError
The `<Html5Audio>` tag requires a string for `src`, but got
Error message
The `<Html5Audio>` tag requires a string for `src`, but got ${JSON.stringify(props.src)} instead. What it means
Html5Audio requires its src prop to be a plain string (a URL or static import path) so Remotion can preload, resolve, and track the media duration. Non-string values (undefined, number, object, React element) are rejected because the underlying <audio> tag and the duration-tracking context both depend on a resolvable string URL.
Source
Thrown at packages/core/src/audio/html5-audio.tsx:68
const {fps} = useVideoConfig();
const environment = useRemotionEnvironment();
const shouldPauseWhenBuffering = resolveV5Default(pauseWhenBuffering);
if (environment.isClientSideRendering) {
throw new Error(
'<Html5Audio> is not supported in @remotion/web-renderer. Use <Audio> from @remotion/media instead. See https://remotion.dev/docs/client-side-rendering/limitations',
);
}
if (typeof freeze !== 'undefined') {
throw new TypeError(
'The "freeze" prop is not supported on <Html5Audio />. Use <Sequence freeze={...}> to freeze media playback.',
);
}
const {durations, setDurations} = useContext(DurationsContext);
if (typeof props.src !== 'string') {
throw new TypeError(
`The \`<Html5Audio>\` tag requires a string for \`src\`, but got ${JSON.stringify(
props.src,
)} instead.`,
);
}
const preloadedSrc = usePreload(props.src);
const onError: React.ReactEventHandler<HTMLAudioElement> = useCallback(
(e) => {
// eslint-disable-next-line no-console
console.log(e.currentTarget.error);
// If there is no `loop` property, we don't need to get the duration
// and this does not need to be a fatal error
const errMessage = `Could not play audio with src ${preloadedSrc}: ${e.currentTarget.error}. See https://remotion.dev/docs/media-playback-error for help.`;
if (loop) {View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Ensure src is always a string: <Html5Audio src={typeof src === 'string' ? src : ''} /> or guard rendering with {src && <Html5Audio src={src} />}.
- If loading asynchronously, delay mounting Html5Audio until the URL is resolved (use delayRender/continueRender or a conditional render).
- Pass staticFile('audio.mp3') or a literal URL string directly.
Example fix
// before
<Html5Audio src={data?.audio} />
// after
{data?.audio ? <Html5Audio src={data.audio} /> : null} Defensive patterns
Strategy: validation
Validate before calling
if (typeof src !== 'string' || src.length === 0) {
// skip mounting or provide a default URL
return null;
} Type guard
const isValidAudioSrc = (src: unknown): src is string => typeof src === 'string' && src.length > 0;
Prevention
- Type the src prop of your wrapper component as `string` (not string | undefined).
- Render <Html5Audio> conditionally only after the URL is resolved.
- Use delayRender to block rendering until async sources are ready.
When it happens
Trigger: Passing <Html5Audio src={undefined} />, src={0}, src={{url}}, src={<Img .../>}, or a conditional that evaluates to undefined/false. Also triggered by passing a staticFile() result wrapped in an array or object, or by forgetting to pass src entirely.
Common situations: Forgetting the src prop; conditional src that short-circuits to undefined when data hasn't loaded; migrating from <Audio> where src typing was looser; passing a remote object instead of its URL field.
Related errors
- The "freeze" prop is not supported on <Html5Audio />. Use <S
- The layout prop of <Sequence /> expects either "absolute-fil
- You passed to the "trimBefore" prop of your <Sequence> an ar
- No 'src' was passed to <Html5Audio>.
- Tried to simultaneously mount ${numberOfAudioTags + 1} <Html
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/bef2a2cc0e9183ee.
Report an issue: GitHub.