{"record":{"id":"047af15dc5045812","repo":"Comfy-Org/ComfyUI","slug":"video-too-short-need-at-least-16-frames-for-moonv","errorCode":null,"errorMessage":"Video too short: need at least 16 frames for Moonvalley","messagePattern":"Video too short: need at least 16 frames for Moonvalley","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/util/conversions.py","lineNumber":360,"sourceCode":"                video_stream = output_container.add_stream(\"h264\", rate=stream.average_rate)\n                video_stream.width = stream.width\n                video_stream.height = stream.height\n                video_stream.pix_fmt = \"yuv420p\"\n                logging.info(\"Added video stream: %sx%s @ %sfps\", stream.width, stream.height, stream.average_rate)\n            elif isinstance(stream, av.AudioStream):\n                # Create output audio stream with same parameters\n                audio_stream = output_container.add_stream(\"aac\", rate=stream.sample_rate)\n                audio_stream.sample_rate = stream.sample_rate\n                audio_stream.layout = stream.layout\n                logging.info(\"Added audio stream: %sHz, %s channels\", stream.sample_rate, stream.channels)\n\n        # Calculate target frame count that's divisible by 16\n        fps = input_container.streams.video[0].average_rate\n        estimated_frames = int(duration_sec * fps)\n        target_frames = (estimated_frames // 16) * 16  # Round down to nearest multiple of 16\n\n        if target_frames == 0:\n            raise ValueError(\"Video too short: need at least 16 frames for Moonvalley\")\n\n        frame_count = 0\n        audio_frame_count = 0\n\n        # Decode and re-encode video frames\n        if video_stream:\n            for frame in input_container.decode(video=0):\n                if frame_count >= target_frames:\n                    break\n\n                # Re-encode frame\n                for packet in video_stream.encode(frame):\n                    output_container.mux(packet)\n                frame_count += 1\n\n            # Flush encoder\n            for packet in video_stream.encode():\n                output_container.mux(packet)","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/util/conversions.py#L342-L378","documentation":"The Moonvalley trim helper rounds the target frame count down to the nearest multiple of 16 (a hard requirement of that model's video encoder). estimated_frames = int(duration_sec * fps); target_frames = (estimated_frames // 16) * 16. When the requested duration at the source fps yields fewer than 16 frames, target_frames becomes 0 and the helper refuses to encode.","triggerScenarios":"Calling the trim path in comfy_api_nodes/util/conversions.py with a source whose fps * requested duration < 16 frames: e.g. a 5 fps clip trimmed to ~1s (5 frames), a 24 fps clip trimmed to 0.5s (12 frames), or a duration of 0.","commonSituations":"Trim controls (start + duration) on a Moonvalley image-to-video workflow set too short; a low-fps GIF or screen-recording source; duration accidentally left at 0 or computed from a wrong time unit (milliseconds vs seconds).","solutions":["Increase the trim duration so that duration_sec * fps >= 16 (e.g. at least 1s at 16fps, ~0.67s at 24fps).","Verify the source clip's average_rate with av or ffprobe; low-fps sources need longer durations.","Check that the duration value is in seconds, not milliseconds or frame counts.","If the source clip itself is shorter than 16 frames, use a longer source video."],"exampleFix":"// before\ntrimmed = trim_video(video, start_time=0.0, duration=0.4)  # 24fps -> 9 frames\n\n// after\nfps = float(video.get_dimensions() and 24)  # know your source fps\nmin_duration = math.ceil(16 / fps)\ntrimmed = trim_video(video, start_time=0.0, duration=max(0.4, min_duration))","handlingStrategy":"validation","validationCode":"fps = float(input_container.streams.video[0].average_rate)\nif int(duration_sec * fps) < 16:\n    raise ValueError(f'Duration {duration_sec}s at {fps}fps gives fewer than 16 frames; need >= {16 / fps:.2f}s')","typeGuard":null,"tryCatchPattern":"try:\n    trimmed = trim_video(video, start_time, duration)\nexcept ValueError as e:\n    if 'at least 16 frames' in str(e):\n        duration = max(duration, math.ceil(16 / fps))\n        trimmed = trim_video(video, start_time, duration)\n    else:\n        raise","preventionTips":["Clamp duration inputs to >= ceil(16 / source_fps) seconds in node UIs.","Check average_rate of the source before configuring trim parameters.","Reject duration <= 0 at input validation time."],"tags":["video","pyav","frame-count","moonvalley","validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}