docling-project/docling · error · ValueError

max_frames must be > 0 when set

Error message

max_frames must be > 0 when set

What it means

ValueError raised by FixedIntervalFrameSampler.__init__ in docling/utils/video_frame_sampling.py when max_frames is provided and is <= 0. max_frames caps the number of extracted frames to bound memory and runtime; None means unlimited, so zero or negative values are treated as configuration errors rather than as 'no frames'.

Source

Thrown at docling/utils/video_frame_sampling.py:288

    frames: list[tuple[float, Image.Image]] = []
    for i in range(count):
        chunk = buf[i * frame_bytes : (i + 1) * frame_bytes]
        frames.append((i / fps, Image.frombytes("RGB", (size, size), chunk)))
    return frames


class FixedIntervalFrameSampler:
    """Sample one frame every ``interval_seconds`` from time zero."""

    def __init__(
        self,
        interval_seconds: float = 10.0,
        max_frames: int | None = None,
    ):
        if interval_seconds <= 0:
            raise ValueError("interval_seconds must be > 0")
        if max_frames is not None and max_frames <= 0:
            raise ValueError("max_frames must be > 0 when set")
        self.interval_seconds = interval_seconds
        self.max_frames = max_frames

    def sample(self, video_path: Path) -> list[VideoFrame]:
        _require_ffmpeg()
        duration = _probe_duration(video_path)

        frames: list[VideoFrame] = []
        t = 0.0
        # If duration is unknown (0.0), rely on extraction returning None at EOF.
        while duration == 0.0 or t < duration:
            if self.max_frames is not None and len(frames) >= self.max_frames:
                break
            image = _extract_frame(video_path, t)
            if image is None:
                break
            frames.append(VideoFrame(timestamp=t, image=image))
            t += self.interval_seconds

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Omit max_frames or pass None when you want no cap; pass a positive int such as max_frames=100 to cap extraction.
  2. Normalize configuration inputs: convert 0/negative to None if 'unlimited' was intended: max_frames = value or None.
  3. Validate derived budgets before construction and surface a clear error if the budget cannot afford at least one frame.

Example fix

# before
sampler = FixedIntervalFrameSampler(max_frames=cfg.max_frames)  # cfg default 0 -> ValueError

# after
cap = cfg.max_frames if isinstance(cfg.max_frames, int) and cfg.max_frames > 0 else None
sampler = FixedIntervalFrameSampler(max_frames=cap)
Defensive patterns

Strategy: validation

Validate before calling

cap = max_frames if isinstance(max_frames, int) and max_frames > 0 else None
sampler = FixedIntervalFrameSampler(interval_seconds=10.0, max_frames=cap)

Type guard

def is_valid_frame_cap(value: int | None) -> bool:
    return value is None or value > 0

Prevention

When it happens

Trigger: Explicitly passing max_frames=0 or a negative int, e.g. FixedIntervalFrameSampler(interval_seconds=5, max_frames=0). Passing max_frames=None is valid (unlimited).

Common situations: CLI/config plumbing where an unset integer option defaults to 0 instead of None; computing max_frames as a budget-derived value (frames = budget // cost) that evaluates to 0 or negative; misreading 0 as 'no cap' when the API uses None for that.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/919436e7137fc92b. Report an issue: GitHub.