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
- Pass an explicit finite number for threshold, e.g. `threshold: 0.005` (the default), or omit the option entirely.
- If threshold is computed, validate it with `Number.isFinite(threshold)` before calling measureSpring().
- 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
- Never derive threshold from an unchecked arithmetic expression; validate first.
- Default to omitting threshold so the library default (0.005) is used.
- Add a unit test that passes edge values (NaN, Infinity, negatives) to your threshold producer.
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
- Threshold is not finite
- Threshold is below 0
- A "duration" of a spring is NaN, which it must not be
- Spring damping must be greater than 0, otherwise the spring(
- A "duration" of a spring must be a "number" but is "${typeof
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/b0482aceda383492.
Report an issue: GitHub.