{"record":{"id":"56a6e3bd288af983","repo":"remotion-dev/remotion","slug":"could-not-determine-duration-of-src-but-loop","errorCode":null,"errorMessage":"Could not determine duration of ${src}, but \"loop\" was set.","messagePattern":"Could not determine duration of (.+?), but \"loop\" was set\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media/src/get-time-in-seconds.ts","lineNumber":25,"sourceCode":"\tsrc,\n\ttrimAfter,\n\ttrimBefore,\n\tfps,\n\tplaybackRate,\n\tifNoMediaDuration,\n}: {\n\tloop: boolean;\n\tmediaDurationInSeconds: number | null;\n\tunloopedTimeInSeconds: number;\n\tsrc: string;\n\ttrimAfter: number | undefined;\n\ttrimBefore: number | undefined;\n\tplaybackRate: number;\n\tfps: number;\n\tifNoMediaDuration: 'fail' | 'infinity';\n}) => {\n\tif (mediaDurationInSeconds === null && loop && ifNoMediaDuration === 'fail') {\n\t\tthrow new Error(\n\t\t\t`Could not determine duration of ${src}, but \"loop\" was set.`,\n\t\t);\n\t}\n\n\tconst loopDurationInFrames = loop\n\t\t? Internals.calculateMediaDuration({\n\t\t\t\ttrimAfter,\n\t\t\t\tmediaDurationInFrames: mediaDurationInSeconds\n\t\t\t\t\t? mediaDurationInSeconds * fps\n\t\t\t\t\t: Infinity,\n\t\t\t\t// Playback rate was already specified before\n\t\t\t\tplaybackRate: 1,\n\t\t\t\ttrimBefore,\n\t\t\t})\n\t\t: Infinity;\n\n\tconst timeInSeconds = loop\n\t\t? ((unloopedTimeInSeconds * playbackRate * fps) % loopDurationInFrames) /","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media/src/get-time-in-seconds.ts#L7-L43","documentation":"Thrown by getTimeInSeconds in @remotion/media when `loop` is true, the media duration could not be determined (null), and the caller requested 'fail' behavior for missing duration. Looping requires knowing the media length to wrap the playhead, so an unknown duration makes looping mathematically impossible. Fires at get-time-in-seconds.ts:25.","triggerScenarios":"Setting loop on a <Video>/<Audio>/<OffthreadVideo> whose duration metadata cannot be read (corrupt header, truncated file, unsupported container), while ifNoMediaDuration is set to 'fail'. The duration probe returns null and loop is true.","commonSituations":"A media file with missing or malformed duration metadata (broken MP4 header, incomplete download), a container Remotion cannot fully parse, or a remote URL that returned partial data. Looping amplifies the requirement for duration.","solutions":["Remove the loop prop if you do not strictly need looping.","Repair or re-encode the source so its duration metadata is present: ffmpeg -i broken.mp4 -c copy fixed.mp4.","Use a well-formed MP4/WebM whose duration is readable by ffprobe."],"exampleFix":"// before\n<Video src={staticFile('clip.mp4')} loop /> // clip.mp4 has no duration metadata\n\n// after\n<Video src={staticFile('clip.mp4')} /> // no loop, or re-encode the file first","handlingStrategy":"validation","validationCode":"null","typeGuard":null,"tryCatchPattern":"// Avoid by ensuring duration is readable; if loop is optional, gate it:\nconst canLoop = mediaDuration != null;\n<Video src={src} loop={canLoop && userWantsLoop} />;","preventionTips":["Verify media duration with ffprobe before rendering.","Only set loop when the source has valid duration metadata.","Re-encode sources that report null duration."],"tags":["video","audio","loop","duration","media"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}