{"record":{"id":"faf2eb8754beeaef","repo":"remotion-dev/remotion","slug":"did-not-calculate-natural-duration-this-is-an-err","errorCode":null,"errorMessage":"did not calculate natural duration, this is an error with Remotion. Please report","messagePattern":"did not calculate natural duration, this is an error with Remotion\\. Please report","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/spring/index.ts","lineNumber":59,"sourceCode":"\n\tconst needsToCalculateNaturalDuration =\n\t\treverse || typeof passedDurationInFrames !== 'undefined';\n\n\tconst naturalDuration = needsToCalculateNaturalDuration\n\t\t? measureSpring({\n\t\t\t\tfps,\n\t\t\t\tconfig,\n\t\t\t\tthreshold: durationRestThreshold,\n\t\t\t})\n\t\t: undefined;\n\n\tconst naturalDurationGetter = needsToCalculateNaturalDuration\n\t\t? {\n\t\t\t\tget: () => naturalDuration as number,\n\t\t\t}\n\t\t: {\n\t\t\t\tget: () => {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'did not calculate natural duration, this is an error with Remotion. Please report',\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t};\n\n\tconst reverseProcessed = reverse\n\t\t? (passedDurationInFrames ?? naturalDurationGetter.get()) - passedFrame\n\t\t: passedFrame;\n\n\tconst delayProcessed = reverseProcessed + (reverse ? delay : -delay);\n\n\tconst durationProcessed =\n\t\tpassedDurationInFrames === undefined\n\t\t\t? delayProcessed\n\t\t\t: delayProcessed / (passedDurationInFrames / naturalDurationGetter.get());\n\n\tif (passedDurationInFrames && delayProcessed > passedDurationInFrames) {\n\t\treturn to;","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/core/src/spring/index.ts#L41-L77","documentation":"spring() builds a naturalDurationGetter: a real getter when needsToCalculateNaturalDuration is true, otherwise a getter that throws this internal error. The throw fires if reverse mode needs the natural duration (e.g. reverse=true and passedDurationInFrames is undefined) but the duration was never calculated. The message explicitly calls this a Remotion bug to report.","triggerScenarios":"Calling spring() with reverse=true and no passedDurationInFrames, hitting the thrower getter via `passedDurationInFrames ?? naturalDurationGetter.get()`.","commonSituations":"Edge-case combination of reverse spring without an explicit duration; an API path that sets needsToCalculateNaturalDuration=false while reverse still needs it.","solutions":["Report the bug to Remotion with a minimal reproduction.","Pass durationInFrames explicitly so the getter is not consulted.","Compute the duration with measureSpring() and pass it through."],"exampleFix":"// before\nspring({ frame, fps, config, reverse: true })\n// after\nspring({ frame, fps, config, reverse: true, durationInFrames: 60 })","handlingStrategy":"validation","validationCode":"// Avoid the unset getter by always passing durationInFrames with reverse:\nconst sp = spring({ frame, fps, config, reverse, durationInFrames: 60 });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass durationInFrames whenever using reverse mode.","Compute the duration via measureSpring() first.","Report the triggering combination upstream if it recurs."],"tags":["spring","internal","bug-report","reverse"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}