{"record":{"id":"e67c13adff111b7f","repo":"Comfy-Org/ComfyUI","slug":"video-length-is-too-short","errorCode":null,"errorMessage":"video length is too short","messagePattern":"video length is too short","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_extras/nodes_wan.py","lineNumber":831,"sourceCode":"    return output_features.transpose(1, 2)  # [1, output_len, 512]\n\n\ndef get_sample_indices(original_fps,\n                       total_frames,\n                       target_fps,\n                       num_sample,\n                       fixed_start=None):\n    required_duration = num_sample / target_fps\n    required_origin_frames = int(np.ceil(required_duration * original_fps))\n    if required_duration > total_frames / original_fps:\n        raise ValueError(\"required_duration must be less than video length\")\n\n    if fixed_start is not None and fixed_start >= 0:\n        start_frame = fixed_start\n    else:\n        max_start = total_frames - required_origin_frames\n        if max_start < 0:\n            raise ValueError(\"video length is too short\")\n        start_frame = np.random.randint(0, max_start + 1)\n    start_time = start_frame / original_fps\n\n    end_time = start_time + required_duration\n    time_points = np.linspace(start_time, end_time, num_sample, endpoint=False)\n\n    frame_indices = np.round(np.array(time_points) * original_fps).astype(int)\n    frame_indices = np.clip(frame_indices, 0, total_frames - 1)\n    return frame_indices\n\n\ndef get_audio_embed_bucket_fps(audio_embed, fps=16, batch_frames=81, m=0, video_rate=30):\n    num_layers, audio_frame_num, audio_dim = audio_embed.shape\n\n    if num_layers > 1:\n        return_all_layers = True\n    else:\n        return_all_layers = False","sourceCodeStart":813,"sourceCodeEnd":849,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_extras/nodes_wan.py#L813-L849","documentation":"Inside get_sample_indices, after the duration check passes, the random-branch computes max_start = total_frames - required_origin_frames; if that is negative the clip has fewer frames than one sampling window even though the earlier duration check passed (the discrepancy comes from ceil rounding to whole source frames). It raises rather than producing negative/invalid start indices.","triggerScenarios":"Edge case where required_duration <= clip duration but ceil(required_duration * original_fps) > total_frames — e.g. fractional-frame rounding with a clip exactly at or a hair under the window size; happens only in the random-start branch (fixed_start >= 0 bypasses it).","commonSituations":"Datasets of very short clips near the minimum length; fps combinations that make required_origin_frames round up past total_frames; boundary videos that pass one check and fail the other.","solutions":["Skip clips whose total_frames < ceil((num_sample / target_fps) * original_fps)","Use a slightly larger num_sample-buffered filter margin when curating short clips","Pass fixed_start=0 for borderline clips to bypass the random-start branch"],"exampleFix":"# before\nidx = get_sample_indices(30, total_frames, 16, 81)\n\n# after: pre-filter with the same rounding\nimport numpy as np\nneed = int(np.ceil((num_sample / target_fps) * original_fps))\nif total_frames < need:\n    continue","handlingStrategy":"validation","validationCode":"import numpy as np\nneed = int(np.ceil((num_sample / target_fps) * original_fps))\nif total_frames < need:\n    skip = True  # mirrors the exact rounding the function uses","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter on ceil-rounded frame counts, not raw durations, to match the function's math","For borderline clips pass fixed_start=0 to skip the random-start branch"],"tags":["wan","video","sampling","edge-case"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}