{"record":{"id":"6358025446d97278","repo":"invoke-ai/InvokeAI","slug":"frame-index-self-frame-index-is-out-of-range-for","errorCode":null,"errorMessage":"frame_index {self.frame_index} is out of range for a {n_frames}-frame video.","messagePattern":"frame_index (.+?) is out of range for a (.+?)-frame video\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/video_frame_extract.py","lineNumber":68,"sourceCode":"        # frame count when available — duration*fps can be off-by-one for VFR\n        # uploads or containers with approximate metadata, causing frame_index=-1\n        # to point past the final frame.\n        index = self.frame_index\n        if index < 0:\n            n_frames = decoder_frame_count(video_path)\n            if n_frames is None:\n                _, _, duration, fps = probe_video(video_path)\n                if not fps or duration <= 0:\n                    raise ValueError(\n                        f\"Cannot resolve negative frame index for video {self.video.video_name}: \"\n                        f\"probe returned duration={duration}, fps={fps}.\"\n                    )\n                n_frames = int(round(duration * fps))\n            if n_frames <= 0:\n                raise ValueError(f\"Video {self.video.video_name} has no decodable frames (probed {n_frames}).\")\n            index = n_frames + index\n            if index < 0:\n                raise ValueError(f\"frame_index {self.frame_index} is out of range for a {n_frames}-frame video.\")\n\n        frame = extract_video_frame(video_path, frame_index=index)\n        if frame is None:\n            raise ValueError(f\"Failed to extract frame {index} from {self.video.video_name}.\")\n\n        image_dto = context.images.save(image=frame)\n        return ImageOutput.build(image_dto=image_dto)\n","sourceCodeStart":50,"sourceCodeEnd":76,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/video_frame_extract.py#L50-L76","documentation":"Thrown after resolving the total frame count when the requested negative frame_index still falls before frame 0 after offsetting (index = n_frames + index < 0). E.g. index -50 on a 20-frame video is out of range. This protects against silent wrap-around or clamping.","triggerScenarios":"invoke() with frame_index = -k where k > n_frames, so n_frames + frame_index < 0.","commonSituations":"Assuming the video is longer than it is; off-by-one in automated batch extraction scripts; using the same negative index across clips of different lengths.","solutions":["Use a smaller-magnitude negative index","Clamp or validate frame_index against the actual frame count before calling","Use a non-negative index if the clip length is known"],"exampleFix":"// before\nVideoFrameExtract(video=v, frame_index=-50)  # video only has 20 frames\n// after\nn = decoder_frame_count(path) or 20\nVideoFrameExtract(video=v, frame_index=-min(50, n))","handlingStrategy":"validation","validationCode":"n = decoder_frame_count(path) or int(round(duration*fps))\nif frame_index < 0 and abs(frame_index) > n:\n    frame_index = -n  # clamp to first frame","typeGuard":"def in_range(frame_index: int, n_frames: int) -> bool:\n    return -n_frames <= frame_index < n_frames","tryCatchPattern":"try:\n    out = extract.invoke(context)\nexcept ValueError as e:\n    if 'out of range' in str(e):\n        out = rebuild(frame_index=-n_frames).invoke(context)\n    else:\n        raise","preventionTips":["Always clamp negative indices against actual frame count","Fetch frame count per clip (lengths differ across clips)","Unit-test batch scripts with mixed clip lengths"],"tags":["video","index-out-of-range","validation"],"backgroundTag":"frame-index-out-of-range","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}