mifi/lossless-cut · error · UserFacingError
Smart cut is not possible when FPS is unknown
Error message
Smart cut is not possible when FPS is unknown
What it means
Thrown during smart-cut export when a segment is flagged as needing a smart (re-encode) cut but the detected video FPS is falsy. Smart cut must convert between frame numbers and timestamps and re-encode the partial GOP, both of which require a known frame rate; without it the cut would be frame-inaccurate. The guard fires after needsSmartCut() reports segmentNeedsSmartCut and before the encode begins.
Source
Thrown at src/renderer/src/hooks/useFfmpegOperations.ts:655
invariant(sourceCodecParams.videoBitrate != null);
invariant(sourceCodecParams.videoTimebase != null);
invariant(filePath != null);
invariant(outFormat != null);
await cutEncodeSmartPart({ cutFrom, cutTo, outPath, outFormat, videoCodec, videoBitrate: encCustomBitrate != null ? encCustomBitrate * 1000 : sourceCodecParams.videoBitrate, videoStreamIndex: videoStream.index, videoTimebase: sourceCodecParams.videoTimebase, allFilesMeta, copyFileStreams: copyFileStreamsFiltered, ffmpegExperimental, hasBFrames: sourceCodecParams.videoStream.has_b_frames });
}
const cutEncodeWholePart = async () => {
await cutEncodeSmartPartWrapper({ cutFrom: desiredCutFrom, cutTo, outPath: finalOutPath });
return { path: finalOutPath, created: true };
};
if (lossyMode) {
console.log('Lossy mode: cutting/encoding the whole segment', { desiredCutFrom, cutTo });
return cutEncodeWholePart();
}
const { losslessCutFrom, segmentNeedsSmartCut } = await needsSmartCut({ path: filePath, desiredCutFrom, videoStream });
if (segmentNeedsSmartCut && !detectedFps) throw new UserFacingError(i18n.t('Smart cut is not possible when FPS is unknown'));
console.log('Smart cut on video stream', videoStream.index);
// If we are cutting within two keyframes, just encode the whole part and return that
// See https://github.com/mifi/lossless-cut/pull/1267#issuecomment-1236381740
if (segmentNeedsSmartCut && losslessCutFrom > cutTo) {
console.log('Segment is between two keyframes, cutting/encoding the whole segment', { desiredCutFrom, losslessCutFrom, cutTo });
return cutEncodeWholePart();
}
invariant(outFormat != null);
const ext = getOutFileExtension({ isCustomFormatSelected: true, outFormat, filePath });
if (segmentNeedsSmartCut) {
console.log('Cutting/encoding lossless part', { from: losslessCutFrom, to: cutTo });
}
const losslessPartOutPath = segmentNeedsSmartCutView on GitHub (pinned to 3b9a59c288)
Solutions
- Disable smart cut (normal/keyframe cut) for streams whose FPS cannot be detected.
- Detect and supply the FPS explicitly: parse avg_frame_rate/r_frame_rate and fall back to a manual value if absent.
- Re-mux/re-encode the source with a fixed frame rate so ffprobe reports it (ffmpeg -r).
- Validate detectedFps is a finite positive number before entering the smart-cut code path.
Example fix
// before
if (segmentNeedsSmartCut && !detectedFps) throw new UserFacingError(...);
// after
const fps = detectedFps || fallbackFpsFromProbe(videoStream);
if (segmentNeedsSmartCut && !fps) {
// degrade gracefully to lossless keyframe cut instead of throwing
return cutEncodeWholePart();
} Defensive patterns
Strategy: validation
Validate before calling
// Detect FPS robustly from ffprobe stream fields
export function detectFps(stream: { avg_frame_rate?: string; r_frame_rate?: string }): number | undefined {
const parse = (s?: string) => {
if (!s) return undefined;
const [n, d] = s.split('/').map(Number);
if (!Number.isFinite(n) || !Number.isFinite(d) || d === 0) return undefined;
const fps = n / d;
return Number.isFinite(fps) && fps > 0 ? fps : undefined;
};
return parse(stream.avg_frame_rate) ?? parse(stream.r_frame_rate);
}
const detectedFps = detectFps(videoStream);
if (!detectedFps && wantSmartCut) throw new Error('Cannot smart cut: FPS unknown'); Type guard
const hasUsableFps = (fps: number | undefined): fps is number => typeof fps === 'number' && Number.isFinite(fps) && fps > 0;
Try / catch
try {
await smartCutExport(...);
} catch (err) {
if (err instanceof UserFacingError && /FPS is unknown/.test(err.message)) {
// fall back to lossless keyframe cut
await losslessCutExport(...);
return;
}
throw err;
} Prevention
- Parse avg_frame_rate and r_frame_rate defensively (handle 0/0 and N/A).
- Let the user supply a manual FPS override for VFR/unknown streams.
- Disable the smart-cut option in the UI when no FPS can be detected.
- Re-encode VFR sources to a constant frame rate before smart cutting.
When it happens
Trigger: Exporting with smart cut enabled on a video stream whose ffprobe reported no avg_frame_rate / r_frame_rate (variable frame rate, or a container that omits the field); a stream whose FPS parsed to 0/NaN; enabling smart cut on an image sequence or still stream.
Common situations: VFR (variable frame rate) screen recordings or mobile clips; streams with FPS as '0/0' in ffprobe; damaged headers; mixing a no-FPS stream into a smart-cut job; force-enabling smart cut on a stream type it does not support.
Related errors
- Cannot find any keyframe after the desired start cut point
- Less than 2 frames found
- Failed to find next keyframe
- Failed to find any prev frame
- Failed to find any prev keyframe
AI-assisted analysis of mifi/lossless-cut@3b9a59c288 (2026-08-12).
Data as JSON: /api/errors/e09e5cd933c5cdd8.
Report an issue: GitHub.