{"record":{"id":"cf859fd9109e9a23","repo":"invoke-ai/InvokeAI","slug":"concatenation-produced-zero-output-frames","errorCode":null,"errorMessage":"Concatenation produced zero output frames.","messagePattern":"Concatenation produced zero output frames\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/video_concat.py","lineNumber":160,"sourceCode":"\n        tmp = tempfile.NamedTemporaryFile(prefix=\"invokeai_video_concat_\", suffix=\".mp4\", delete=False)\n        tmp.close()\n        tmp_path = Path(tmp.name)\n        try:\n            # Frames stream from the decoders straight into the encoder; only the\n            # transition windows are buffered. See _iter_joined_frames.\n            writer = make_mp4_writer(tmp_path, output_fps)\n            num_frames = 0\n            try:\n                clip_iters = [iter_video_frames(p, is_canceled=context.util.is_canceled) for p in paths]\n                for frame in self._iter_joined_frames(clip_iters, is_canceled=context.util.is_canceled):\n                    writer.append_data(frame)\n                    num_frames += 1\n            finally:\n                writer.close()\n\n            if num_frames == 0:\n                raise ValueError(\"Concatenation produced zero output frames.\")\n\n            duration = num_frames / output_fps\n            context.logger.info(\n                f\"Encoded concatenated MP4: {num_frames} frames @ {output_fps:.2f} fps \"\n                f\"({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=duration,\n                fps=output_fps,\n            )\n            context.logger.info(f\"Saved concatenated video: {video_dto.video_name}\")\n            return VideoOutput.build(video_dto)\n        finally:\n            try:\n                tmp_path.unlink(missing_ok=True)","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/video_concat.py#L142-L178","documentation":"After encoding, video_concat checks that at least one frame was written. If the writer loop appended zero frames (e.g. all inputs were empty or unreadable), it raises ValueError rather than emitting a corrupt/empty MP4.","triggerScenarios":"All input video files exist but contain zero decodable frames (empty/corrupt files), so the per-frame read loops never append data and num_frames stays 0.","commonSituations":"Upstream video generation produced empty files; truncated downloads; container metadata present but no frames; disk issues during writes.","solutions":["Verify each input video plays and has frames (ffprobe -count_frames) before concatenating","Regenerate or re-export the upstream video nodes","Replace corrupt input files"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for p in paths:\n    n = count_frames(p)  # e.g. ffprobe -count_frames -select_streams v:0 -show_entries stream=nb_read_frames\n    if n == 0:\n        raise ValueError(f\"input {p} has zero frames; regenerate before concat\")","typeGuard":"def has_frames(path) -> bool:\n    return count_frames(path) > 0","tryCatchPattern":"try:\n    output = concat.invoke(context)\nexcept ValueError as e:\n    if \"zero output frames\" in str(e):\n        regenerate_upstream_videos()\n        output = concat.invoke(context)\n    else:\n        raise","preventionTips":["Verify upstream video generation completed and files are non-trivial size","Check disk space and write permissions where outputs are written","Use ffprobe to confirm decodable frames on all inputs before concat"],"tags":["video","encoding","empty-output"],"backgroundTag":"empty-output-file","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}