mifi/lossless-cut · error · UserFacingError
Segment start time must precede end time
Error message
Segment start time must precede end time
What it means
Thrown by setCutTime() in the type==='start' branch when the new start time is not null and is >= the existing segment end. LosslessCut requires every segment to have start < end (a positive-length span), so moving the start to or past the end is rejected. The guard fires before updateSegAtIndex so no invalid state is written.
Source
Thrown at src/renderer/src/hooks/useSegments.tsx:469
const updateSegAtIndex = useCallback<UpdateSegAtIndex>((index, newProps) => {
if (index < 0) return;
const cutSegmentsNew = [...cutSegments];
const existing = cutSegments[index];
invariant(existing != null);
cutSegmentsNew.splice(index, 1, { ...existing, ...newProps });
safeSetCutSegments(cutSegmentsNew, fileDuration);
}, [cutSegments, safeSetCutSegments, fileDuration]);
const setCutTime = useCallback((type: 'start' | 'end' | 'move', time: number | undefined) => {
if (!isDurationValid(fileDuration) || currentCutSeg == null) return;
const clampStart = (start: number) => Math.min(Math.max(start, 0), fileDuration);
const clampEnd = (end?: number | undefined) => (end != null ? Math.min(Math.max(end, 0), fileDuration) : undefined);
if (type === 'start') {
invariant(time != null);
if (currentCutSeg.end != null && time >= currentCutSeg.end) {
throw new UserFacingError(i18n.t('Segment start time must precede end time'));
}
updateSegAtIndex(currentSegIndexSafe, { start: clampStart(time) });
}
if (type === 'end') {
if (time != null && time <= currentCutSeg.start) {
throw new UserFacingError(i18n.t('Segment start time must precede end time'));
}
updateSegAtIndex(currentSegIndexSafe, { end: clampEnd(time) });
}
if (type === 'move') {
invariant(time != null);
updateSegAtIndex(currentSegIndexSafe, {
start: clampStart(time),
...(currentCutSeg.end != null && { end: clampEnd(time + (currentCutSeg.end - currentCutSeg.start)) }),
});
}
}, [currentSegIndexSafe, currentCutSeg, fileDuration, updateSegAtIndex]);
View on GitHub (pinned to 3b9a59c288)
Solutions
- Clamp the requested start to be strictly less than end before calling setCutTime('start', ...).
- If the user intends to swap, move the end first, then the start.
- Validate in the UI: disable the start handle once it reaches the end handle.
- Provide an undo when the drag triggers the error.
Example fix
// before
setCutTime('start', requestedStart);
// after
const safeStart = currentCutSeg.end != null ? Math.min(requestedStart, currentCutSeg.end - epsilon) : requestedStart;
setCutTime('start', safeStart); Defensive patterns
Strategy: validation
Validate before calling
const epsilon = 0.001;
if (type === 'start' && currentCutSeg.end != null && requestedStart >= currentCutSeg.end) {
// clamp instead of throwing
requestedStart = currentCutSeg.end - epsilon;
}
setCutTime('start', requestedStart); Try / catch
try {
setCutTime('start', requestedStart);
} catch (err) {
if (err instanceof UserFacingError && /start time must precede end/.test(err.message)) {
showError('Start cannot be at or after the segment end.');
return;
}
throw err;
} Prevention
- Clamp requested start to < end before calling setCutTime('start', ...).
- In the timeline UI, prevent the start handle from crossing the end handle.
- If swapping boundaries is intended, move end first then start.
- Provide undo for drags that violate the ordering.
When it happens
Trigger: Calling setCutTime('start', t) with t >= currentCutSeg.end; dragging/typing a start marker that lands on or after the segment's end; programmatically setting start from a slider whose value overshot the end.
Common situations: User drags the start handle past the end handle on the timeline; a numeric input/keyboard nudge pushes start beyond end; clamping logic that did not account for the end boundary; importing a segment and nudging its start.
Related errors
- No rows found
- Invalid start or end value. Must contain a number of seconds
- No valid segments found
- Tried to create too many segments (max {{maxSegmentsAllowed}
- 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/cc152f4c012e04db.
Report an issue: GitHub.