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
- Use longer source clips — at least num_frames / 24 seconds (e.g. 22 frames ≈ 0.92s, with margin).
- Or lower the requested num_frames to the next smaller 17*n+5 value the clips can fill.
- 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
- Match num_frames (17*n+5) to your shortest clip before launch.
- Filter sub-second clips from the dataset during prep.
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
- num_frames must be positive, got {num_frames}.
- num_frames must be of the form {H3_FRAMES_PER_CHUNK} * n + {
- MiniMax-H3 was trained on aspect ratios from 1:4 to 4:1; thi
- {Path(path).name} carries no video track.
- {Path(path).name} carries no audio track. MiniMax-H3 denoise
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/96ffb892de968e9e.
Report an issue: GitHub.