roboflow/supervision · error · RuntimeError

Reader thread raised: {item}

Error message

Reader thread raised: {item}

What it means

Raised by the frame queue consumer inside _prefetched_frames_generator (src/supervision/utils/video.py) when the background reader thread put an exception object into the queue instead of a frame. The consumer wraps it in RuntimeError, chaining the original exception, so the message names the underlying failure that occurred while opening or reading the video on the worker thread.

Source

Thrown at src/supervision/utils/video.py:368

            while not stop_event.is_set():
                try:
                    frame_queue.put(sentinel, timeout=0.1)
                    return
                except Full:
                    pass

    thread = threading.Thread(target=reader, daemon=True)
    thread.start()
    try:
        while True:
            try:
                item = frame_queue.get(timeout=0.5)
            except Empty:
                if not thread.is_alive():
                    break
                continue
            if isinstance(item, BaseException):
                raise RuntimeError(f"Reader thread raised: {item!r}") from item
            if item is None:
                break
            yield item
    finally:
        stop_event.set()
        thread.join(timeout=2.0)


def process_video(
    source_path: str,
    target_path: str,
    callback: Callable[[npt.NDArray[np.uint8], int], npt.NDArray[np.uint8]],
    *,
    max_frames: int | None = None,
    prefetch: int = 32,
    writer_buffer: int = 32,
    show_progress: bool = False,
    progress_message: str = "Processing video",

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Read the tail of the message and the chained __cause__ to find the real failure, then fix that (usually file/codec related).
  2. Verify the source video opens synchronously first: sv.get_video_frames_generator(path) with prefetch=0 to get the raw error.
  3. Guard per-file processing in a try/except so one bad video does not kill a batch job.
  4. If the file is truncated, repair or re-encode it with ffmpeg before processing.

Example fix

// before
for frame in sv.get_video_frames_generator(path, prefetch=8):
    ...  # RuntimeError: Reader thread raised: ...

// after
try:
    for frame in sv.get_video_frames_generator(path, prefetch=8):
        ...
except RuntimeError as e:
    log.warning('skipping %s: %s', path, e.__cause__ or e)
Defensive patterns

Strategy: try-catch

Validate before calling

probe = cv2.VideoCapture(path)
readable = probe.isOpened()
probe.release()
if not readable:
    raise RuntimeError(f'video not readable: {path}')

Try / catch

try:
    for frame in sv.get_video_frames_generator(path, prefetch=prefetch):
        process(frame)
except RuntimeError as e:
    if 'Reader thread raised' in str(e) and e.__cause__ is not None:
        log.warning('reader failure on %s: %r', path, e.__cause__)
        continue  # skip to next file in a batch
    raise

Prevention

When it happens

Trigger: Calling sv.get_video_frames_generator(path, prefetch=N) where the reader thread hits an error — e.g. the video cannot be opened, a grab()/retrieve() fails mid-stream, or the file is truncated. The exception travels through the queue and is re-raised on the main thread during iteration.

Common situations: A video becomes unreadable or is deleted after the generator is created; truncated recordings from killed processes; network streams dropping mid-read; the error text 'Reader thread raised: ...' is a wrapper — the real cause follows after the colon and via __cause__.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/7de955bdeb6bc586. Report an issue: GitHub.