remotion-dev/remotion · error · TypeError

Expected Player event emitter context

Error message

Expected Player event emitter context

What it means

usePlayerMethods retrieves the Player event emitter from PlayerEventEmitterContext; this context is only provided inside @remotion/player's <Player>. If the hook runs without a provider, emitter is undefined and a TypeError is thrown telling you the Player event emitter context is missing.

Source

Thrown at packages/player/src/use-player-methods.ts:43

	const {
		setPlaying,
		frameRef,
		audioAndVideoTags,
		isPlaying: readIsPlaying,
		isBuffering,
	} = useContext(Internals.SetTimelineContext);
	const audioContext = useContext(Internals.SharedAudioContext);
	const audioTagsContext = useContext(Internals.SharedAudioTagsContext);
	const environment = useRemotionEnvironment();
	const video = Internals.useVideo();
	const config = Internals.useUnsafeVideoConfig();
	const emitter = useContext(PlayerEventEmitterContext);
	const playStart = useRef(0);
	const fallbackFrame = useRef<number | null>(null);
	const nextPlayIsAutoPlayAttempt = useRef(false);

	if (!emitter) {
		throw new TypeError('Expected Player event emitter context');
	}

	const getCurrentFrame = useCallback(() => {
		if (!video) {
			return (
				fallbackFrame.current ??
				(typeof window === 'undefined'
					? 0
					: (window.remotion_initialFrame ?? 0))
			);
		}

		const unclamped =
			frameRef.current[video.id] ??
			(environment.isPlayer
				? 0
				: Internals.Timeline.getFrameForComposition(video.id));

View on GitHub (pinned to a6a7485a9a)

Solutions

  1. Render the component inside a <Player> from @remotion/player
  2. Move play/pause/seek logic into components within the Player's React tree
  3. Use useVideoPlayerContext only under Player; for studio/CLI rendering, gate player hooks behind an is-player check
  4. Align @remotion/player and @remotion/core versions so context modules match

Example fix

// before
const controls = usePlayer(); // rendered outside <Player>
// after
<Player component={MyVideo} ...>
  <PlayerControls/> {/* inside Player tree, context provided */}
</Player>
Defensive patterns

Strategy: type-guard

Validate before calling

// Only mount player-control components under <Player>
if (!insidePlayerTree) return <StaticControls/>;

Type guard

const hasPlayerEmitter = (e: PlayerEventEmitter | undefined): e is PlayerEventEmitter =>
  e !== undefined && typeof e.addEventListener === 'function';

Try / catch

try {
  const controls = usePlayerMethods(video);
} catch (e) {
  if (e instanceof TypeError && e.message.includes('Player event emitter context')) {
    // render non-player fallback controls
  } else throw e;
}

Prevention

When it happens

Trigger: Calling usePlayerMethods (or hooks building on it, like usePlayer) in a component rendered outside a <Player> from @remotion/player — e.g. inside a plain Remotion composition render, a Storybook story, or a test without the provider.

Common situations: Using player-only hooks (play/pause/seek) inside compositions rendered by the Remotion CLI/studio renderer instead of inside a <Player>; missing @remotion/player version alignment so the context object differs; rendering controls outside the Player tree.

Related errors


AI-assisted analysis of remotion-dev/remotion@a6a7485a9a (2026-09-02). Data as JSON: /api/errors/9adfe149af735c91. Report an issue: GitHub.