invoke-ai/InvokeAI · error · ValueError

end_frame ({self.end_frame} → {end}) must be >= start_frame

Error message

end_frame ({self.end_frame} → {end}) must be >= start_frame ({self.start_frame} → {start}) after resolving negative indices.

What it means

Raised by the Video Frame Extract Range invocation after negative start/end indices are resolved against the probed frame count. It means the requested end frame comes before the start frame, so the extraction range is empty or invalid. The library throws eagerly in invoke() rather than producing a zero/negative-length clip.

Source

Thrown at invokeai/app/invocations/video_frame_extract_range.py:161

    def invoke(self, context: InvocationContext) -> ExtractVideoRangeOutput:
        video_path = context.videos.get_path(self.video.video_name)
        width, height, duration, source_fps = probe_video(video_path)

        n_frames = decoder_frame_count(video_path)
        if n_frames is None:
            if not source_fps or duration <= 0:
                raise ValueError(
                    f"Cannot determine frame count for {self.video.video_name}: "
                    f"probe returned duration={duration}, fps={source_fps}."
                )
            n_frames = int(round(duration * source_fps))
        if n_frames <= 0:
            raise ValueError(f"Video {self.video.video_name} has no decodable frames (probed {n_frames}).")

        start = self._resolve_index(self.start_frame, n_frames, "start_frame")
        end = self._resolve_index(self.end_frame, n_frames, "end_frame")
        if end < start:
            raise ValueError(
                f"end_frame ({self.end_frame} → {end}) must be >= start_frame "
                f"({self.start_frame} → {start}) after resolving negative indices."
            )

        # Derive the output frame rate from the source video when ``fps`` is 0
        # (the default), so a trimmed clip plays back at the same speed as its
        # source. Fall back to 16 fps (the Wan video default) when the source
        # rate couldn't be probed.
        if self.fps > 0:
            output_fps = float(self.fps)
        elif source_fps and source_fps > 0:
            output_fps = float(source_fps)
        else:
            output_fps = 16.0

        # libx264 + yuv420p needs even dimensions. Reject odd sources up front with a
        # clear message instead of surfacing an opaque ffmpeg error mid-encode.
        _validate_even_dimensions(width, height, self.video.video_name)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Print the probed frame count and check start_frame <= end_frame before running
  2. If using negative indices, remember resolution is value + n_frames; pick values so resolved start <= resolved end
  3. Use start_frame=0 and end_frame=-1 for the full video instead of hand-computed absolute numbers
  4. Fix upstream nodes/board values that produce the reversed range

Example fix

// before
invocation.start_frame = -10
invocation.end_frame = -50  # resolves to end < start
// after
invocation.start_frame = -50
invocation.end_frame = -10  # or use 0 / -1 for full clip
Defensive patterns

Strategy: validation

Validate before calling

n_frames = probe_frame_count(video)
def resolve(v): return v + n_frames if v < 0 else v
if resolve(end_frame) < resolve(start_frame):
    raise ValueError(f"range {start_frame}-{end_frame} resolves to end < start")

Type guard

def has_valid_range(start: int, end: int, n: int) -> bool:
    rs = start + n if start < 0 else start
    re = end + n if end < 0 else end
    return 0 <= rs <= re < n

Try / catch

try:
    result = invocation.invoke(context)
except ValueError as e:
    if "must be >= start_frame" in str(e):
        # swap or clamp the range and retry
        invocation.start_frame, invocation.end_frame = 0, -1
        result = invocation.invoke(context)
    else:
        raise

Prevention

When it happens

Trigger: Calling the invocation with start_frame > end_frame (e.g. start_frame=100, end_frame=10), or with negative values whose wrap-around resolution inverts the order (e.g. start_frame=-5 resolves near the end while end_frame=3 stays at the beginning, or start_frame=-10, end_frame=-50 resolves to end < start).

Common situations: Hand-computed negative indices assuming Python slice semantics that differ from this implementation; dynamically computed ranges where a computed end is smaller than start; users expecting end to be clamped rather than validated.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/c6cabed93c3eba6d. Report an issue: GitHub.