{"record":{"id":"3e1fa2e80e6b534b","repo":"invoke-ai/InvokeAI","slug":"decoded-only-num-frames-of-expected-frames-req","errorCode":null,"errorMessage":"Decoded only {num_frames} of {expected_frames} requested frames for range {start}-{end} of {self.video.video_name} (probed {n_frames} frames). The container's metadata may be inaccurate.","messagePattern":"Decoded only (.+?) of (.+?) requested frames for range (.+?)-(.+?) of (.+?) \\(probed (.+?) frames\\)\\. The container's metadata may be inaccurate\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/video_frame_extract_range.py","lineNumber":203,"sourceCode":"        tmp_path = Path(tmp.name)\n        try:\n            # imageio's iter_index isn't exposed by iio.imiter, so we enumerate and skip.\n            # Frames stream straight from the decoder into the encoder; see _write_frame_range.\n            writer = make_mp4_writer(tmp_path, output_fps)\n            try:\n                num_frames = _write_frame_range(\n                    iter_video_frames(video_path, is_canceled=context.util.is_canceled),\n                    writer,\n                    start,\n                    end,\n                    is_canceled=context.util.is_canceled,\n                )\n            finally:\n                writer.close()\n\n            expected_frames = end - start + 1\n            if num_frames != expected_frames:\n                raise ValueError(\n                    f\"Decoded only {num_frames} of {expected_frames} requested frames for range {start}-{end} \"\n                    f\"of {self.video.video_name} \"\n                    f\"(probed {n_frames} frames). The container's metadata may be inaccurate.\"\n                )\n\n            out_duration = num_frames / output_fps\n            context.logger.info(\n                f\"Encoded trimmed MP4: {num_frames} frames @ {output_fps:.2f} fps \"\n                f\"({out_duration:.2f}s) at {width}x{height}\"\n            )\n            video_dto = context.videos.save(\n                source_path=tmp_path,\n                width=width,\n                height=height,\n                duration=out_duration,\n                fps=output_fps,\n            )\n            context.logger.info(f\"Saved trimmed video: {video_dto.video_name}\")","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/video_frame_extract_range.py#L185-L221","documentation":"Raised after decoding when the number of frames actually written to the output clip is fewer than end - start + 1. The container advertised enough frames during probing but the decoder could not produce them all, so the library refuses to emit a short, silently-trimmed clip and warns that container metadata may be wrong.","triggerScenarios":"invoke() decoding a range whose expected_frames = end - start + 1 exceeds what the decoder actually yields: truncated/corrupt video files, broken keyframe indexes, videos whose header reports more frames than physically exist, or codec failures mid-stream.","commonSituations":"Downloading partial MP4s (cut off mid-file), screen recordings with corrupted moov metadata, re-encoded videos with inaccurate frame counts in metadata, remote/network-stored videos that failed to fully transfer.","solutions":["Re-encode the video with ffmpeg (e.g. ffmpeg -i in.mp4 -c:v libx264 out.mp4) to rebuild accurate metadata","Verify the file is complete/re-download it; probe with ffprobe -count_frames to see the true frame count","Reduce end_frame so the requested range fits within actually decodable frames","Check available disk space and decode logs for codec errors"],"exampleFix":"// before\n# truncated video, end_frame=-1 requests all 'probed' frames that don't decode\n// after\n# repair metadata first\n# ffmpeg -i broken.mp4 -c copy fixed.mp4  (or full re-encode), then retry","handlingStrategy":"try-catch","validationCode":"true_count = int(subprocess.check_output(['ffprobe','-v','error','-count_frames','-select_streams','v:0','-show_entries','stream=nb_read_frames','-of','csv=p=0', video_path]))\nif end - start + 1 > true_count:\n    end = true_count - 1","typeGuard":"def range_fully_decodable(start: int, end: int, true_frame_count: int) -> bool:\n    return 0 <= start and end - start + 1 <= true_frame_count","tryCatchPattern":"try:\n    clip = invocation.invoke(context)\nexcept ValueError as e:\n    if \"Decoded only\" in str(e):\n        # re-encode to repair metadata, then retry\n        subprocess.run(['ffmpeg','-y','-i',src,'-c:v','libx264',fixed])\n        invocation.video = load(fixed)\n        clip = invocation.invoke(context)\n    else:\n        raise","preventionTips":["Verify downloads are complete (checksums) before extraction","Run ffprobe -count_frames to detect metadata/actual mismatches early","Re-encode suspicious videos with ffmpeg before use","Avoid end_frame=-1 on files from untrusted/partial sources"],"tags":["video","decode","metadata"],"backgroundTag":"video-decode-frame-shortfall","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}