mifi/lossless-cut · error · UserFacingError
Less than 2 frames found
Error message
Less than 2 frames found
What it means
Thrown by getSafeCutTime() when the frames array passed in has fewer than 2 elements. The function computes a safe keyframe-aligned cut by inspecting neighbouring frames, which is meaningless without at least two frames to reason about ordering. This is a defensive precondition check before any index arithmetic.
Source
Thrown at src/renderer/src/ffmpeg.ts:153
if (!nearByKeyframe) {
keyframes = await readKeyframesAroundTime({ filePath, streamIndex, aroundTime: time, window: 60 });
nearByKeyframe = findKeyframe(keyframes, time, mode);
}
if (!nearByKeyframe) return undefined;
return nearByKeyframe.time;
}
// todo this is not in use
// https://stackoverflow.com/questions/14005110/how-to-split-a-video-using-ffmpeg-so-that-each-chunk-starts-with-a-key-frame
// http://kicherer.org/joomla/index.php/de/blog/42-avcut-frame-accurate-video-cutting-with-only-small-quality-loss
export function getSafeCutTime(frames: Frame[], cutTime: number, nextMode: boolean) {
const sigma = 0.01;
const isCloseTo = (time1: number, time2: number) => Math.abs(time1 - time2) < sigma;
let index: number;
if (frames.length < 2) throw new UserFacingError(i18n.t('Less than 2 frames found'));
if (nextMode) {
index = frames.findIndex((f) => f.keyframe && f.time >= cutTime - sigma);
if (index === -1) throw new UserFacingError(i18n.t('Failed to find next keyframe'));
if (index >= frames.length - 1) throw new UserFacingError(i18n.t('We are on the last frame'));
const { time } = frames[index]!;
if (isCloseTo(time, cutTime)) {
return undefined; // Already on keyframe, no need to modify cut time
}
return time;
}
const findReverseIndex = <T>(arr: T[], cb: (value: T, i: number, obj: T[]) => unknown) => {
// eslint-disable-next-line unicorn/no-array-callback-reference
const ret = [...arr].reverse().findIndex(cb);
if (ret === -1) return -1;
return arr.length - 1 - ret;
};View on GitHub (pinned to 3b9a59c288)
Solutions
- Ensure the frames array is fully populated (await the keyframe/frame probe) before calling getSafeCutTime.
- Skip smart-cut / safe-cut for clips with fewer than 2 frames and fall back to a plain lossless cut.
- Diagnose the source media with `ffprobe -show_frames` to confirm it actually contains multiple frames.
- Guard the caller: if (frames.length < 2) return cutTime unchanged instead of invoking the function.
Example fix
// before const safe = getSafeCutTime(frames, cutTime, nextMode); // after const safe = frames.length >= 2 ? getSafeCutTime(frames, cutTime, nextMode) : undefined;
Defensive patterns
Strategy: validation
Validate before calling
// Ensure at least 2 frames before calling getSafeCutTime
if (!Array.isArray(frames) || frames.length < 2) {
throw new Error(`Need >= 2 frames for safe cut, got ${frames?.length ?? 0}`);
} Type guard
const hasMinFrames = (frames: unknown): frames is Frame[] => Array.isArray(frames) && frames.length >= 2;
Prevention
- Await the full frame/keyframe probe before invoking getSafeCutTime.
- Skip smart/safe cut for very short clips and fall back to a plain lossless cut.
- Treat a <2-frame stream as a degenerate/still source rather than a cuttable video.
When it happens
Trigger: Calling getSafeCutTime(frames, cutTime, nextMode) with a frames array of length 0 or 1; passing the result of a keyframe probe that returned only the single current frame; a video stream whose ffprobe frame list was truncated or empty due to a read error.
Common situations: Very short source clips (1 frame); corrupted/damaged media where ffprobe could only decode one frame; calling the function on a still-image or single-frame stream; a race where the frames array was populated asynchronously and read before completion.
Related errors
- Failed to find next keyframe
- Failed to find any prev frame
- Failed to find any prev keyframe
- Cannot find any keyframe after the desired start cut point
- Cannot find any keyframe within 60 seconds of frame {{time}}
AI-assisted analysis of mifi/lossless-cut@3b9a59c288 (2026-08-12).
Data as JSON: /api/errors/3ac6580eaf8f3f52.
Report an issue: GitHub.