remotion-dev/remotion · error · Error
Video frames must be in presentation order.
Error message
Video frames must be in presentation order.
What it means
After rebasing (timestamp - firstVideoTimestamp), rebaseVideoTimestamp rejects frames that precede the video start by more than a tiny epsilon (-Number.EPSILON * 16), throwing 'Video frames must be in presentation order.' A small negative slack is tolerated to absorb floating-point jitter. This enforces monotonically non-decreasing frame order expected by the encoder/processor.
Source
Thrown at packages/video-matting/src/video-timing.ts:14
export const rebaseVideoTimestamp = ({
timestamp,
firstVideoTimestamp,
}: {
timestamp: number;
firstVideoTimestamp: number;
}): number => {
if (!Number.isFinite(timestamp) || !Number.isFinite(firstVideoTimestamp)) {
throw new TypeError('Video timestamps must be finite numbers.');
}
const rebased = timestamp - firstVideoTimestamp;
if (rebased < -Number.EPSILON * 16) {
throw new Error('Video frames must be in presentation order.');
}
return Math.max(0, rebased);
};
export const getClippedVideoFrameTiming = ({
timestamp,
duration,
videoStartTimestamp,
videoEndTimestamp,
}: {
timestamp: number;
duration: number;
videoStartTimestamp: number;
videoEndTimestamp: number;
}): {timestamp: number; duration: number} | null => {
if (!Number.isFinite(timestamp)) {
throw new TypeError('The video frame timestamp must be finite.');View on GitHub (pinned to b2f4e34732)
Solutions
- Sort frames by timestamp (stable sort) before processing
- Set firstVideoTimestamp to the minimum frame timestamp of the batch, not the first decoded frame
- Check whether you are using DTS instead of PTS and switch to presentation timestamps
- Handle seeking explicitly: reset processing state and firstVideoTimestamp after a seek
- If jitter is legitimate, clamp tiny negatives instead of reordering frames
Example fix
// before
frames.forEach((f) => process(rebasedTimestamp({timestamp: f.dts, firstVideoTimestamp})));
// after
const ordered = [...frames].sort((a, b) => a.pts - b.pts);
ordered.forEach((f) => process(rebasedTimestamp({timestamp: f.pts, firstVideoTimestamp: ordered[0].pts}))); Defensive patterns
Strategy: validation
Validate before calling
let last = -Infinity;
for (const f of frames) {
if (f.pts < last) throw new Error('Frames not in presentation order');
last = f.pts;
} Type guard
const isInPresentationOrder = (frames: {pts: number}[]): boolean =>
frames.every((f, i) => i === 0 || f.pts >= frames[i - 1].pts); Try / catch
try {
const ts = rebasedTimestamp({timestamp: frame.pts, firstVideoTimestamp});
} catch (err) {
if (err instanceof Error && err.message === 'Video frames must be in presentation order.') {
console.warn('Out-of-order frame dropped');
return;
}
throw err;
} Prevention
- Stable-sort frames by PTS before processing
- Use PTS, not DTS, for presentation ordering
- Reset firstVideoTimestamp and state after seeks or segment switches
- Watch for floating-point jitter; rely on the library's epsilon tolerance instead of exact comparisons
When it happens
Trigger: Feeding frames whose timestamps go backwards relative to firstVideoTimestamp beyond floating-point jitter — e.g. interleaved tracks processed out of order, B-frame/PTS-vs-DTS confusion, or frames from a seek arriving before the seek point.
Common situations: Manually sorting frames with an unstable sort, mixing keyframe-first decoding with presentation-order playback, or concatenating frames from multiple video segments without resetting firstVideoTimestamp.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Video timestamps must be finite numbers.
- The video frame timestamp must be finite.
- The video presentation range is invalid.
- Streams with UNIX timestamps are not currently supported by
- Streams with UNIX timestamps are not currently supported by
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09).
Data as JSON: /api/errors/1058452d7320291f.
Report an issue: GitHub.