roboflow/supervision · error · ValueError
Video source has no video stream: {source}
Error message
Video source has no video stream: {source} What it means
Raised when the PyAV capture opens a file successfully but the container contains no video stream (self._container.streams.video is empty). This happens with audio-only media, some corrupt files, or text files passed as video; the fallback refuses to continue with an empty stream.
Source
Thrown at src/supervision/_cv2/_video.py:80
def __init__(self, source: str | os.PathLike[str] | int) -> None:
"""Open a file source and retain a lazy PyAV frame iterator."""
self._container: Any = None
self._stream: Any = None
self._frames: Iterator[Any] | None = None
self._source = source
self._position = 0
self._frame_count_cache: int | None = None
self._opened = False
self._error: Exception | None = None
try:
if isinstance(source, int):
raise BackendUnavailableError(
"PyAV fallback supports file paths, not webcam device indexes."
)
self._container = av.open(str(source), mode="r")
if not self._container.streams.video:
raise ValueError(f"Video source has no video stream: {source}")
self._stream = self._container.streams.video[0]
self._frames = iter(self._container.decode(video=self._stream.index))
self._opened = True
except Exception as exc:
self._error = exc
logger.warning("Failed to open video source %r: %s", source, exc)
self.release()
def isOpened(self) -> bool:
"""Return whether the underlying video file is open for reading."""
return self._opened
def _frame_count(self) -> int:
"""Return the stream count, decoding a second handle if metadata lacks it."""
if self._frame_count_cache is not None:
return self._frame_count_cache
count = int(getattr(self._stream, "frames", 0) or 0)View on GitHub (pinned to 7f254d9784)
Solutions
- Verify the file is a video before opening: check extension and/or probe with av.open in a try block, inspecting container.streams.video.
- Re-download or re-mux corrupt files (ffmpeg -i in.mp4 -c copy out.mp4 often repairs truncation).
- Handle open failure via cap.isOpened() == False and skip/log the source instead of crashing a batch job.
Example fix
# before
cap = cv2.VideoCapture(user_supplied_path) # may be audio-only
# after
import av
cap = cv2.VideoCapture(user_supplied_path)
if not cap.isOpened():
logger.warning('not a readable video: %s', user_supplied_path)
continue Defensive patterns
Strategy: validation
Validate before calling
import av
def has_video_stream(path: str) -> bool:
try:
with av.open(path):
return True
except av.AVError:
return False
if has_video_stream(path):
cap = cv2.VideoCapture(path) Try / catch
cap = cv2.VideoCapture(path)
if not cap.isOpened():
logger.warning('skipping unreadable/non-video source: %s', path)
return None Prevention
- Filter by extension before opening directory globs
- Probe media with PyAV/ffprobe before processing user uploads
- Always check cap.isOpened() and skip-and-log in batch jobs
When it happens
Trigger: cv2.VideoCapture('audio.mp3'), a truncated/corrupt video, an image or arbitrary binary renamed to .mp4, or a stream URL that resolves to audio-only content.
Common situations: Globbing a directory and opening every file without extension checks, user-uploaded media of unknown type, or partially downloaded videos where the moov/index is missing.
Related errors
- Unsupported video codec: {code}
- PyAV video fallback only supports color (3-channel BGR) fram
- Video writer is not open
- Video frame must have shape ({self._height}, {self._width},
- Video frames must use uint8 dtype
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/b05c0bc2cd0a7580.
Report an issue: GitHub.