remotion-dev/remotion · error · TypeError

Threshold is NaN

Error message

Threshold is NaN

What it means

measureSpring() accepts an optional `threshold` option (default 0.005) that decides when a spring is considered settled. The function validates threshold in sequence; this guard fires when threshold is the numeric value NaN. NaN slips past the earlier `typeof threshold !== 'number'` check because NaN is of type 'number', and it would break the settling loop since every `difference >= NaN` comparison is false.

Source

Thrown at packages/core/src/spring/measure-spring.ts:43

	config = {},
	threshold = 0.005,
}: MeasureSpringProps): number {
	if (typeof threshold !== 'number') {
		throw new TypeError(
			`threshold must be a number, got ${threshold} of type ${typeof threshold}`,
		);
	}

	if (threshold === 0) {
		return Infinity;
	}

	if (threshold === 1) {
		return 0;
	}

	if (isNaN(threshold)) {
		throw new TypeError('Threshold is NaN');
	}

	if (!Number.isFinite(threshold)) {
		throw new TypeError('Threshold is not finite');
	}

	if (threshold < 0) {
		throw new TypeError('Threshold is below 0');
	}

	const cacheKey = [
		fps,
		config.damping,
		config.mass,
		config.overshootClamping,
		config.stiffness,
		threshold,
	].join('-');

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Pass an explicit finite number for threshold, e.g. `threshold: 0.005` (the default), or omit the option entirely.
  2. If threshold is computed, validate it with `Number.isFinite(threshold)` before calling measureSpring().
  3. Trace the source of the NaN by logging the expression producing threshold right before the call.

Example fix

// before
const t = parseFloat(userInput);
const dur = measureSpring({fps: 30, threshold: t});

// after
const t = Number.parseFloat(userInput);
if (!Number.isFinite(t)) throw new Error('invalid threshold');
const dur = measureSpring({fps: 30, threshold: t});
Defensive patterns

Strategy: validation

Validate before calling

const isFinitePositiveNumber = (v: unknown): v is number =>
  typeof v === 'number' && Number.isFinite(v) && !Number.isNaN(v);

const threshold = computeThreshold();
if (!isFinitePositiveNumber(threshold)) {
  throw new Error(`threshold must be a finite number, got ${threshold}`);
}
const dur = measureSpring({fps: 30, threshold});

Type guard

const isValidThreshold = (v: unknown): v is number =>
  typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1;

Prevention

When it happens

Trigger: Calling `measureSpring({fps, threshold: NaN})` directly, or passing a computed threshold that evaluated to NaN such as `0/0`, `Math.sqrt(-1)`, `parseFloat('abc')`, or `Number(undefined)`.

Common situations: Deriving threshold from a dynamic calculation (e.g. a prop or config field) that can become NaN under edge inputs; refactors that leave threshold uninitialized before the call.

Related errors


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