remotion-dev/remotion · error · TypeError

The "times" prop of a loop must be an integer, but got ${tim

Error message

The "times" prop of a loop must be an integer, but got ${times}.

What it means

The <Loop> component repeats its child `times` times. After confirming `times` is a number, Remotion requires it to be an integer because a fractional repeat count is undefined. `Infinity` is explicitly permitted as a sentinel for "loop forever" (excluded by the `times !== Infinity` guard), but any other non-integer like 1.5 throws a TypeError at loop/index.tsx:59.

Source

Thrown at packages/core/src/loop/index.tsx:59

	showInTimeline,
	...props
}) => {
	const currentFrame = useCurrentFrame();
	const {durationInFrames: compDuration} = useVideoConfig();

	validateDurationInFrames(durationInFrames, {
		component: 'of the <Loop /> component',
		allowFloats: true,
	});

	if (typeof times !== 'number') {
		throw new TypeError(
			`You passed to "times" an argument of type ${typeof times}, but it must be a number.`,
		);
	}

	if (times !== Infinity && times % 1 !== 0) {
		throw new TypeError(
			`The "times" prop of a loop must be an integer, but got ${times}.`,
		);
	}

	if (times < 0) {
		throw new TypeError(
			`The "times" prop of a loop must be at least 0, but got ${times}`,
		);
	}

	const maxTimes = Math.ceil(compDuration / durationInFrames);
	const actualTimes = Math.min(maxTimes, times);
	const style = props.layout === 'none' ? undefined : props.style;
	const maxFrame = durationInFrames * (actualTimes - 1);
	const iteration = Math.floor(currentFrame / durationInFrames);
	const start = iteration * durationInFrames;
	const from = Math.min(start, maxFrame);

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Round the computed value: times={Math.ceil(compDuration / loopDuration)} (or Math.floor).
  2. Pass an integer literal: times={3}.
  3. Use Infinity to loop forever: times={Infinity}.

Example fix

// before
<Loop durationInFrames={30} times={compDuration / 30} />
// after
<Loop durationInFrames={30} times={Math.ceil(compDuration / 30)} />
Defensive patterns

Strategy: validation

Validate before calling

const safeTimes =
  typeof times === 'number' && (times === Infinity || Number.isInteger(times))
    ? times
    : Math.round(Number(times));

Type guard

const isLoopTimes = (v: unknown): v is number =>
  typeof v === 'number' && (v === Infinity || Number.isInteger(v));

Prevention

When it happens

Trigger: Passing times={1.5}, times={2.7}, or any float to <Loop>. Deriving times from a division (e.g. compDuration / loopDuration) that yields a non-integer without rounding.

Common situations: Computing loop count from composition math (compDuration / clipDuration) that does not divide evenly; binding times to a Studio slider that produces floats; copy-pasting a fractional value.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/ace9fce5fbd87ff9. Report an issue: GitHub.