sgl-project/sglang · error · ValueError

nframes should in interval [{FRAME_FACTOR}, {total_frames}],

Error message

nframes should in interval [{FRAME_FACTOR}, {total_frames}], but got {nframes}.

What it means

Raised by ernie45_vl.smart_nframes after clamping and floor-rounding the target frame count to FRAME_FACTOR: the result fell outside [FRAME_FACTOR, total_frames]. Because floor_by_factor can drop nframes below FRAME_FACTOR (e.g. total_frames=7, factor=4, clamp gives 4 but floor of an odd count can yield 0 in degenerate cases), or the video has fewer frames than FRAME_FACTOR, no valid frame count exists.

Source

Thrown at python/sglang/srt/multimodal/processors/ernie45_vl.py:167

        "fps" in ele and "nframes" in ele
    ), "Only accept either `fps` or `nframes`"
    if "nframes" in ele:
        nframes = round_by_factor(ele["nframes"], FRAME_FACTOR)
    else:
        fps = ele.get("fps", FPS)
        min_frames = ceil_by_factor(ele.get("min_frames", FPS_MIN_FRAMES), FRAME_FACTOR)
        max_frames = floor_by_factor(
            ele.get("max_frames", min(FPS_MAX_FRAMES, total_frames)), FRAME_FACTOR
        )
        nframes = total_frames / video_fps * fps
        if nframes > total_frames:
            logger.warning(
                f"smart_nframes: nframes[{nframes}] > total_frames[{total_frames}]"
            )
        nframes = min(min(max(nframes, min_frames), max_frames), total_frames)
        nframes = floor_by_factor(nframes, FRAME_FACTOR)
    if not (FRAME_FACTOR <= nframes and nframes <= total_frames):
        raise ValueError(
            f"nframes should in interval [{FRAME_FACTOR}, {total_frames}], but got {nframes}."
        )
    return nframes


# process video, qwen-specific
async def preprocess_video(
    vr,
    image_factor: int = IMAGE_FACTOR,
) -> torch.Tensor:

    total_frames, video_fps = len(vr), vr.get_avg_fps()
    nframes = smart_nframes({}, total_frames=total_frames, video_fps=video_fps)
    idx = np.linspace(0, total_frames - 1, num=nframes, dtype=np.int64)
    idx = np.unique(idx)
    video_np = vr.get_batch(idx).asnumpy()
    video = torch.from_numpy(video_np).pin_memory()
    video = video.permute(0, 3, 1, 2)  # Convert to TCHW format

View on GitHub (pinned to 0132848349)

Solutions

  1. Skip or reject videos with total_frames < FRAME_FACTOR before preprocessing
  2. Ensure max_frames >= FRAME_FACTOR and is a multiple of the frame factor
  3. For short clips, pad or duplicate frames so total_frames >= FRAME_FACTOR

Example fix

# before
out = processor.preprocess_video(video_list, ...)  # video decodes to 1 frame
# after
if n_total < FRAME_FACTOR:
    raise SkipSample(f'video too short: {n_total} frames')
out = processor.preprocess_video(video_list, ...)
Defensive patterns

Strategy: validation

Validate before calling

total = count_frames(path)
if total < FRAME_FACTOR:  # 2 for ernie45
    raise SkipSample(f'video too short: {total} frames')

Type guard

def has_enough_frames(path: str, minimum: int = 2) -> bool:
    return count_frames(path) >= minimum

Try / catch

try:
    out = preprocess_video(v, ...)
except ValueError as e:
    if 'nframes should in interval' in str(e):
        mark_video_corrupt(v); continue
    raise

Prevention

When it happens

Trigger: Calling preprocess_video on a video whose total decoded frames < FRAME_FACTOR (2); FPS-based nframes computed from a very short clip (e.g. total_video_seconds*fps < 2); nframes clamped to max_frames that is itself below factor.

Common situations: Very short or corrupt video files that decode to 1 frame; metadata claiming a duration the decoder doesn't deliver; custom max_frames set to 1.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/ce70890def765938. Report an issue: GitHub.