remotion-dev/remotion · error · Error
You must pass either 'component' or 'lazyComponent'
Error message
You must pass either 'component' or 'lazyComponent'
What it means
Thrown by useLazyComponent when the compProps object contains neither a `component` nor a defined `lazyComponent` key. Remotion's <Composition>, <Player>, and <Still> require exactly one of these props so they know what to render; reaching this branch means the discriminated union was violated at runtime (TypeScript normally prevents it). It is a hard failure that stops the composition from mounting.
Source
Thrown at packages/core/src/use-lazy-component.ts:91
if (
'lazyComponent' in compProps &&
typeof compProps.lazyComponent !== 'undefined'
) {
if (typeof compProps.lazyComponent === 'undefined') {
throw new Error(
`A value of \`undefined\` was passed to the \`lazyComponent\` prop. Check the value you are passing to the <${componentName}/> component.`,
);
}
return React.lazy(
compProps.lazyComponent as () => Promise<{
default: ComponentType<Props>;
}>,
);
}
throw new Error("You must pass either 'component' or 'lazyComponent'");
// Very important to leave the dependencies as they are, or instead
// the player will remount on every frame.
// For the 'component' case, we intentionally do NOT depend on
// compProps.component — the stable wrapper reads from componentRef instead.
// @ts-expect-error
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [compProps.lazyComponent]);
return lazy;
};
View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Pass either `component={MyComponent}` or `lazyComponent={React.lazy(() => import('./MyComponent'))}` to the <Composition>/<Player>/<Still>.
- If building props dynamically, default to a real component: `const comp = entry.component ?? DefaultComp; <Composition component={comp} .../>`.
- Search the codebase for the composition id named in the surrounding error trace and confirm its registration object has a component key.
- Add a runtime assert in your registration helper: `if (!entry.component && !entry.lazyComponent) throw new Error('missing component for ' + entry.id);`.
Example fix
// before
<Composition id="x" durationInFrames={120} fps={30} width={1920} height={1080} {...maybeEmptyProps} />
// after
<Composition id="x" durationInFrames={120} fps={30} width={1920} height={1080} component={MyVideo} /> Defensive patterns
Strategy: type-guard
Validate before calling
const hasComponent = (p) => Boolean(p && ('component' in p && p.component) || ('lazyComponent' in p && typeof p.lazyComponent === 'function'));
if (!hasComponent(props)) throw new Error('Composition needs component or lazyComponent'); Type guard
function hasRenderable(p: object): p is { component: unknown } | { lazyComponent: () => Promise<unknown> } {
return ('component' in p && p.component != null) || ('lazyComponent' in p && typeof (p as any).lazyComponent === 'function');
} Prevention
- Always pass component or lazyComponent explicitly; never spread an unvalidated object as the composition props.
- When registering compositions from a config array, type each entry as the CompProps union so TS enforces the key.
- Add a unit test that asserts every entry in your composition registry has a component or lazyComponent.
When it happens
Trigger: Calling <Composition>/<Still>/<Player> while spreading a props object whose `component`/`lazyComponent` keys are both absent or both explicitly undefined, or constructing compProps dynamically (e.g. from a lookup that returned nothing). Also reachable from JS consumers that bypass the TS union check.
Common situations: Registering compositions from a config array/map where some entries forgot the component field; conditionally building props and the condition evaluated to neither branch; migrating from `component` to `lazyComponent` and leaving both unset during refactor; dynamic registration loops in entry files.
Related errors
- <Composition> was mounted inside the `component` that was pa
- <Composition> mounted inside another composition. See https:
- No id for composition passed.
- No src passed
- No video config found. You are probably calling useVideoConf
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/2c8135c250a56cd4.
Report an issue: GitHub.