{"record":{"id":"c6cabed93c3eba6d","repo":"invoke-ai/InvokeAI","slug":"end-frame-self-end-frame-end-must-be-st","errorCode":null,"errorMessage":"end_frame ({self.end_frame} → {end}) must be >= start_frame ({self.start_frame} → {start}) after resolving negative indices.","messagePattern":"end_frame \\((.+?) → (.+?)\\) must be >= start_frame \\((.+?) → (.+?)\\) after resolving negative indices\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/video_frame_extract_range.py","lineNumber":161,"sourceCode":"    def invoke(self, context: InvocationContext) -> ExtractVideoRangeOutput:\n        video_path = context.videos.get_path(self.video.video_name)\n        width, height, duration, source_fps = probe_video(video_path)\n\n        n_frames = decoder_frame_count(video_path)\n        if n_frames is None:\n            if not source_fps or duration <= 0:\n                raise ValueError(\n                    f\"Cannot determine frame count for {self.video.video_name}: \"\n                    f\"probe returned duration={duration}, fps={source_fps}.\"\n                )\n            n_frames = int(round(duration * source_fps))\n        if n_frames <= 0:\n            raise ValueError(f\"Video {self.video.video_name} has no decodable frames (probed {n_frames}).\")\n\n        start = self._resolve_index(self.start_frame, n_frames, \"start_frame\")\n        end = self._resolve_index(self.end_frame, n_frames, \"end_frame\")\n        if end < start:\n            raise ValueError(\n                f\"end_frame ({self.end_frame} → {end}) must be >= start_frame \"\n                f\"({self.start_frame} → {start}) after resolving negative indices.\"\n            )\n\n        # Derive the output frame rate from the source video when ``fps`` is 0\n        # (the default), so a trimmed clip plays back at the same speed as its\n        # source. Fall back to 16 fps (the Wan video default) when the source\n        # rate couldn't be probed.\n        if self.fps > 0:\n            output_fps = float(self.fps)\n        elif source_fps and source_fps > 0:\n            output_fps = float(source_fps)\n        else:\n            output_fps = 16.0\n\n        # libx264 + yuv420p needs even dimensions. Reject odd sources up front with a\n        # clear message instead of surfacing an opaque ffmpeg error mid-encode.\n        _validate_even_dimensions(width, height, self.video.video_name)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/video_frame_extract_range.py#L143-L179","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Print the probed frame count and check start_frame <= end_frame before running","If using negative indices, remember resolution is value + n_frames; pick values so resolved start <= resolved end","Use start_frame=0 and end_frame=-1 for the full video instead of hand-computed absolute numbers","Fix upstream nodes/board values that produce the reversed range"],"exampleFix":"// before\ninvocation.start_frame = -10\ninvocation.end_frame = -50  # resolves to end < start\n// after\ninvocation.start_frame = -50\ninvocation.end_frame = -10  # or use 0 / -1 for full clip","handlingStrategy":"validation","validationCode":"n_frames = probe_frame_count(video)\ndef resolve(v): return v + n_frames if v < 0 else v\nif resolve(end_frame) < resolve(start_frame):\n    raise ValueError(f\"range {start_frame}-{end_frame} resolves to end < start\")","typeGuard":"def has_valid_range(start: int, end: int, n: int) -> bool:\n    rs = start + n if start < 0 else start\n    re = end + n if end < 0 else end\n    return 0 <= rs <= re < n","tryCatchPattern":"try:\n    result = invocation.invoke(context)\nexcept ValueError as e:\n    if \"must be >= start_frame\" in str(e):\n        # swap or clamp the range and retry\n        invocation.start_frame, invocation.end_frame = 0, -1\n        result = invocation.invoke(context)\n    else:\n        raise","preventionTips":["Always use 0 and -1 for 'full video' instead of absolute frame numbers","Recompute ranges after any change to the source video","Remember negative indices resolve as value + n_frames","Validate start <= end in your workflow before the denoise/extract step"],"tags":["validation","video","range"],"backgroundTag":"invalid-frame-range","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}