unslothai/unsloth · error · ValueError

MiniMax-H3 reference videos run {H3_REF_VIDEO_MIN_SECONDS:g}

Error message

MiniMax-H3 reference videos run {H3_REF_VIDEO_MIN_SECONDS:g} to {H3_REF_VIDEO_MAX_SECONDS:g} seconds; this one is {duration:.1f}s.

What it means

After decoding, duration = decoded_count / source_fps is compared against H3_REF_VIDEO_MIN_SECONDS (2.0s) with a 1e-6 tolerance, and a ValueError is raised when the reference video is shorter than the model's minimum. H3's reference window is 2-15s: too-short clips are refused rather than padded, because the model expects at least ~2s of motion to condition on.

Source

Thrown at studio/backend/core/inference/video_minimax_h3.py:422

                    f"{H3_REF_VIDEO_MAX_SECONDS:g}s. Trim it first."
                )
            target_source = int(next_target * source_fps / H3_FPS)
            if target_source > source_index:
                continue
            image = frame.to_image().convert("RGB")
            if fitted_size is None:
                fitted_size = h3_reference_frame_size(*image.size)
            if image.size != fitted_size:
                image = image.resize(fitted_size, Image.LANCZOS)
            while int(next_target * source_fps / H3_FPS) <= source_index:
                frames.append(image)
                next_target += 1

    if decoded_count == 0:
        raise ValueError("That reference video decoded to no frames.")
    duration = decoded_count / source_fps
    if duration + 1e-6 < H3_REF_VIDEO_MIN_SECONDS:
        raise ValueError(
            f"MiniMax-H3 reference videos run {H3_REF_VIDEO_MIN_SECONDS:g} to "
            f"{H3_REF_VIDEO_MAX_SECONDS:g} seconds; this one is {duration:.1f}s."
        )
    frames = frames[: int(round(duration * H3_FPS))]

    waveform, sample_rate = (None, None)
    with av.open(io.BytesIO(blob)) as container:
        if container.streams.audio:
            waveform, sample_rate = _decode_audio_stream(container, np)
    return frames, waveform, sample_rate


def decode_h3_reference_audio(blob: bytes) -> tuple[Any, int]:
    """Decode one uploaded audio file to a float32 ``(samples, channels)`` waveform + its rate."""
    import io

    import av
    import numpy as np

View on GitHub (pinned to 203007d190)

Solutions

  1. Re-trim to at least 2.0s of footage (the valid window is 2-15s).
  2. Loop or slow the clip to reach 2s if no more source footage exists.
  3. Validate duration client-side before upload: 2.0 <= frames/fps <= 15.0.

Example fix

# before: over-trimmed to 1.2s after the max-duration error
ffmpeg -t 1.2 -i take.mp4 ref.mp4

# after: keep inside the 2-15s window
ffmpeg -ss 10 -t 5 -i take.mp4 ref.mp4
Defensive patterns

Strategy: validation

Validate before calling

import av, io

H3_REF_VIDEO_MIN_SECONDS = 2.0

with av.open(io.BytesIO(blob)) as c:
    s = c.streams.video[0]
    fps = float(s.average_rate or s.guessed_rate or 25)
    n = s.frames or 0
    if n and n / fps < H3_REF_VIDEO_MIN_SECONDS:
        raise ValueError("reference video must be at least 2s; loop or slow the clip")

Try / catch

try:
    frames, wf, sr = decode_h3_reference_video(blob)
except ValueError as e:
    if "this one is" in str(e) and "seconds" in str(e):
        return HTTPException(400, "reference must run 2-15s") from e
    raise

Prevention

When it happens

Trigger: Uploading a 0.5s or 1-frame looping clip as a reference; very short GIF-converted-to-mp4 files; clips trimmed so aggressively they fall under 2.0s (error 514's trim advice can overshoot into this one).

Common situations: Users over-trimming after hitting the max-duration error; frame-accurate trims landing at 1.9s; single-shot motion snippets.

Related errors


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