{"record":{"id":"9b2fa11928ffb1b6","repo":"Comfy-Org/ComfyUI","slug":"video-frame-count-must-be-at-most-max-frame-count","errorCode":null,"errorMessage":"Video frame count must be at most {max_frame_count}, got {frame_count}","messagePattern":"Video frame count must be at most (.+?), got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/util/validation_utils.py","lineNumber":151,"sourceCode":"    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\n    if min_duration is not None and dur + eps < min_duration:\n        raise ValueError(f\"Audio duration must be at least {min_duration}s, got {dur + eps:.2f}s\")","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/util/validation_utils.py#L133-L169","documentation":"Raised by validate_video_frame_count() in comfy_api_nodes/util/validation_utils.py when a video passed to an API node has more frames than the provider's max_frame_count. It is the upper-bound counterpart of the minimum check on the next line; the guard exists so over-long clips fail locally with a clear message instead of burning a paid API request or producing a provider-side 400. get_frame_count() failures are swallowed (logged) and skip validation entirely.","triggerScenarios":"Connecting a long video to an api-node that calls validate_video_frame_count(video, max_frame_count=N) — e.g. lip-sync / video-extension nodes where providers cap input length (commonly 300 frames, 25 fps * N seconds). Any clip whose get_frame_count() exceeds N raises immediately at node execution time, before any HTTP request is made.","commonSituations":"User loads a multi-minute source video into a provider that only accepts ~10 s; frame rate mismatch after re-encoding inflates frame counts; or a workflow built for short clips is reused with long content. Providers frequently tighten limits between API versions, so an old workflow can start failing after a node-pack update.","solutions":["Trim or subsample the video before the node: cut the clip to <= max_frame_count frames (use a video trim/subsample node or re-export at a lower duration).","Raise the output fps relationship arithmetic: frames = duration * fps; reduce duration or drop frames (e.g. take every 2nd frame) to get under the cap.","Check the node's tooltip / provider docs for the exact frame limit and recalculate your clip length in frames, not seconds.","If the limit is genuinely too small for your content, look for a chunked/iterative variant of the node or process the video in segments."],"exampleFix":"# before: 30 s clip at 25 fps = 750 frames into a 300-frame-cap node\nvalidate_video_frame_count(video, max_frame_count=300)  # raises\n\n# after: trim to 12 s before the node\n# (use a trim/video-combine node so get_frame_count() <= 300)","handlingStrategy":"validation","validationCode":"import cv2\ncap = cv2.VideoCapture(path)\nframes = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)); fps = cap.get(cv2.CAP_PROP_FPS); cap.release()\nassert frames <= MAX_FRAMES, f'{frames} frames exceeds cap {MAX_FRAMES} ({frames/fps:.1f}s at {fps}fps)'","typeGuard":null,"tryCatchPattern":"try: validate_video_frame_count(v, max_frame_count=N) except ValueError as e: raise UserVisibleError(str(e)) from e","preventionTips":["Remember frames = duration x fps; compute both before connecting long clips.","Trim upstream with a video-trim node sized to the provider cap.","Process long content in segments rather than one oversized clip."],"tags":["video","api-nodes","validation","input-validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}