roboflow/supervision · error · RuntimeError
Reader thread raised
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.
Solutions
- Read the tail of the message and the chained __cause__ to find the real failure, then fix that (usually file/codec related).
- Verify the source video opens synchronously first: sv.get_video_frames_generator(path) with prefetch=0 to get the raw error.
- Guard per-file processing in a try/except so one bad video does not kill a batch job.
- 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
- Treat 'Reader thread raised' as a wrapper; always inspect __cause__ for the real error.
- Wrap per-video processing in try/except in batch pipelines.
- Verify file integrity (ffprobe) before enabling prefetch on untrusted inputs.
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
- Could not open video at
- Could not open video at
- Could not open video writer for
- Requested frames are outbound
- All sigma values must be positive
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/7de955bdeb6bc586.
Report an issue: GitHub.
Appendix: 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)