{"record":{"id":"b0482aceda383492","repo":"remotion-dev/remotion","slug":"threshold-is-nan","errorCode":null,"errorMessage":"Threshold is NaN","messagePattern":"Threshold is NaN","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/core/src/spring/measure-spring.ts","lineNumber":43,"sourceCode":"\tconfig = {},\n\tthreshold = 0.005,\n}: MeasureSpringProps): number {\n\tif (typeof threshold !== 'number') {\n\t\tthrow new TypeError(\n\t\t\t`threshold must be a number, got ${threshold} of type ${typeof threshold}`,\n\t\t);\n\t}\n\n\tif (threshold === 0) {\n\t\treturn Infinity;\n\t}\n\n\tif (threshold === 1) {\n\t\treturn 0;\n\t}\n\n\tif (isNaN(threshold)) {\n\t\tthrow new TypeError('Threshold is NaN');\n\t}\n\n\tif (!Number.isFinite(threshold)) {\n\t\tthrow new TypeError('Threshold is not finite');\n\t}\n\n\tif (threshold < 0) {\n\t\tthrow new TypeError('Threshold is below 0');\n\t}\n\n\tconst cacheKey = [\n\t\tfps,\n\t\tconfig.damping,\n\t\tconfig.mass,\n\t\tconfig.overshootClamping,\n\t\tconfig.stiffness,\n\t\tthreshold,\n\t].join('-');","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/spring/measure-spring.ts#L25-L61","documentation":"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.","triggerScenarios":"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)`.","commonSituations":"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.","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."],"exampleFix":"// before\nconst t = parseFloat(userInput);\nconst dur = measureSpring({fps: 30, threshold: t});\n\n// after\nconst t = Number.parseFloat(userInput);\nif (!Number.isFinite(t)) throw new Error('invalid threshold');\nconst dur = measureSpring({fps: 30, threshold: t});","handlingStrategy":"validation","validationCode":"const isFinitePositiveNumber = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && !Number.isNaN(v);\n\nconst threshold = computeThreshold();\nif (!isFinitePositiveNumber(threshold)) {\n  throw new Error(`threshold must be a finite number, got ${threshold}`);\n}\nconst dur = measureSpring({fps: 30, threshold});","typeGuard":"const isValidThreshold = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1;","tryCatchPattern":null,"preventionTips":["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."],"tags":["spring","animation","nan","validation","measure-spring"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}