unslothai/unsloth · error · ValueError

{Path(path).name} decoded to {len(frames)} frames at {H3_FPS

Error message

{Path(path).name} decoded to {len(frames)} frames at {H3_FPS} fps, but a training clip needs {num_frames} ({num_frames / H3_FPS:.2f}s). Use longer clips.

What it means

Raised by decode_clip() when, after resampling the source to H3_FPS, fewer than num_frames frames were produced by the end of the file — i.e. the clip is too short for the requested training length. decode_clip trains the first num_frames/H3_FPS seconds, so a shorter source simply cannot fill the window. Longer sources are fine (a note suggests trimming), only short ones fail.

Source

Thrown at studio/backend/core/training/diffusion_h3_clips.py:330

        next_target = 0
        for source_index, frame in enumerate(container.decode(video = 0)):
            if len(frames) >= num_frames:
                break
            if int(next_target * source_fps / H3_FPS) > source_index:
                continue
            image = frame.to_image().convert("RGB")
            # Before the crop, not after: the canvas is in display orientation, so cropping the
            # coded frame would trim the wrong pair of edges as well as train it sideways.
            image = apply_display_rotation(image, display_rotation_degrees(frame, stream), Image)
            image = _cover_resize(image, width, height, Image)
            while (
                int(next_target * source_fps / H3_FPS) <= source_index and len(frames) < num_frames
            ):
                frames.append(np.asarray(image, dtype = "uint8"))
                next_target += 1

    if len(frames) < num_frames:
        raise ValueError(
            f"{Path(path).name} decoded to {len(frames)} frames at {H3_FPS} fps, but a training "
            f"clip needs {num_frames} ({num_frames / H3_FPS:.2f}s). Use longer clips."
        )
    if on_note is not None and source_duration_s > (num_frames / H3_FPS) * 1.05:
        on_note(
            f"{Path(path).name} is {source_duration_s:.1f}s; MiniMax-H3 trains its first "
            f"{num_frames / H3_FPS:.2f}s and its caption is paired with that. Trim the clip to "
            f"the part the caption describes."
        )

    waveform = _decode_clip_audio(path, target_samples, av, np)
    return np.stack(frames), waveform


def display_rotation_degrees(frame: Any, stream: Any) -> int:
    """The clip's display rotation, one of 0/90/180/270, as a PLAYER would apply it.

    PyAV hands back the CODED frame: unlike the ffmpeg CLI, ``to_image()`` and ``to_ndarray()``

View on GitHub (pinned to 203007d190)

Solutions

  1. Use longer source clips — at least num_frames / 24 seconds (e.g. 22 frames ≈ 0.92s, with margin).
  2. Or lower the requested num_frames to the next smaller 17*n+5 value the clips can fill.
  3. Pre-scan durations and drop clips shorter than the training window, reporting them by name.

Example fix

# before
frames, wave = decode_clip(p, num_frames=39, ...)  # clip is 1.0s (~24 frames)

# after
frames, wave = decode_clip(p, num_frames=22, ...)  # fits a ~1s clip at 24 fps
Defensive patterns

Strategy: validation

Validate before calling

H3_FPS = 24

def clip_long_enough(path: str, num_frames: int) -> bool:
    import av
    with av.open(path) as c:
        s = c.streams.video[0]
        dur = float(s.duration * s.time_base) if s.duration and s.time_base else 0.0
    return dur == 0.0 or dur >= num_frames / H3_FPS  # unknown duration -> let decode decide

Try / catch

try:
    frames, waveform = decode_clip(p, num_frames=n, width=w, height=h)
except ValueError as e:
    if "Use longer clips" in str(e):
        skip_and_log(p)
    else:
        raise

Prevention

When it happens

Trigger: A clip whose decoded duration at H3_FPS yields fewer than num_frames frames; num_frames set to a larger 17*n+5 value than the clip supports (e.g. 39 frames needed but the clip is ~1s); high-fps sources that are actually very brief.

Common situations: Short meme/sfx clips (< 1s) mixed into a dataset; training at a longer clip length after initial experiments; mis-detected fps causing under-sampling; teaser/trailer snippets.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/96ffb892de968e9e. Report an issue: GitHub.