{"record":{"id":"88e4038ac0b140a8","repo":"Comfy-Org/ComfyUI","slug":"video-frame-count-must-be-at-least-min-frame-coun","errorCode":null,"errorMessage":"Video frame count must be at least {min_frame_count}, got {frame_count}","messagePattern":"Video frame count must be at least (.+?), got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/util/validation_utils.py","lineNumber":149,"sourceCode":"    if min_duration is not None and min_duration - epsilon > duration:\n        raise ValueError(f\"Video duration must be at least {min_duration}s, got {duration}s\")\n    if max_duration is not None and duration > max_duration + epsilon:\n        raise ValueError(f\"Video duration must be at most {max_duration}s, got {duration}s\")\n\n\ndef validate_video_frame_count(\n    video: Input.Video,\n    min_frame_count: int | None = None,\n    max_frame_count: int | None = None,\n):\n    try:\n        frame_count = video.get_frame_count()\n    except Exception as e:\n        logging.error(\"Error getting frame count of video: %s\", e)\n        return\n\n    if min_frame_count is not None and min_frame_count > frame_count:\n        raise ValueError(f\"Video frame count must be at least {min_frame_count}, got {frame_count}\")\n    if max_frame_count is not None and frame_count > max_frame_count:\n        raise ValueError(f\"Video frame count must be at most {max_frame_count}, got {frame_count}\")\n\n\ndef get_number_of_images(images):\n    if isinstance(images, torch.Tensor):\n        return images.shape[0] if images.ndim >= 4 else 1\n    return len(images)\n\n\ndef validate_audio_duration(\n    audio: Input.Audio,\n    min_duration: float | None = None,\n    max_duration: float | None = None,\n) -> None:\n    sr = int(audio[\"sample_rate\"])\n    dur = int(audio[\"waveform\"].shape[-1]) / sr\n    eps = 1.0 / sr","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/util/validation_utils.py#L131-L167","documentation":"Raised by validate_video_frame_count() in comfy_api_nodes/util/validation_utils.py when an API video-generation node receives a video whose frame count is below the provider's minimum. The check calls video.get_frame_count() and compares against min_frame_count; it exists because upstream APIs (e.g. Kling, LTX, Wan lip-sync/audio nodes) reject too-short clips with worse error messages or waste a paid API call. Note that if get_frame_count() itself throws, the helper logs and returns silently — this ValueError only fires when the count was successfully read and is still too low.","triggerScenarios":"Feeding a short video into an api-node that calls validate_video_frame(video, min_frame_count=N) (e.g. video-to-video, first-last-frame, or lip-sync nodes in comfy_api_nodes/nodes_kling.py / nodes_wan.py / nodes_ltxv.py) with fewer frames than the provider requires. Typical call: validate_video_frame_count(video, min_frame_count=2) with a single-frame video.","commonSituations":"User connects a single still image loaded as a 1-frame video (VHS VideoLoad or LoadVideo with a short clip), trims a clip too aggressively, or a upstream node emits fewer frames than requested. Also happens when fps/duration misconfiguration makes an exported clip shorter than expected.","solutions":["Increase the source video length: load a longer clip or repeat/extend frames (e.g. VHS_VideoCombine settings or a frame-duplication node) so frame_count >= min_frame_count.","Check the node's documentation tooltip for the provider's minimum frame count (often 2 for start/end-frame nodes) and pick inputs accordingly.","If the video unexpectedly reports a low frame count, re-encode or reload the file — a corrupt container can cause get_frame_count() to under-report, though that usually takes the silent-log path instead.","If you control the workflow, switch to a node variant that accepts images (first/last frame image inputs) instead of a video when you only have stills."],"exampleFix":"// before: 1-frame video fed to a node requiring min_frame_count=2\nvalidate_video_frame_count(video, min_frame_count=2)  # raises ValueError\n\n// after: duplicate the frame or supply a real clip\n# in the workflow: use a LoadImage + image-based node variant, or\n# pad the video to >= 2 frames before connecting it","handlingStrategy":"validation","validationCode":"# ComfyUI VIDEO object: probe via cv2/VHS-style loader, or trust the source node\n# If you have the file path:\nimport cv2\ncap = cv2.VideoCapture(path)\nframe_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\ncap.release()\nassert frame_count >= MIN_FRAMES, f'need >= {MIN_FRAMES} frames, got {frame_count}'","typeGuard":null,"tryCatchPattern":"In a custom node wrapper: try: validate_video_frame_count(v, min_frame_count=N) except ValueError as e: return (ui_message(f'Input video rejected: {e}'),)","preventionTips":["Check clip length in frames (not seconds) before wiring video into API nodes.","Prefer image-based node variants when you only have stills.","Keep source clips longer than the strictest provider minimum in your workflow."],"tags":["video","api-nodes","validation","input-validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}