roboflow/supervision · error · ValueError
Video frame must have shape ({self._height}, {self._width},
Error message
Video frame must have shape ({self._height}, {self._width}, 3), got {frame.shape} What it means
The PyAV writer validates every frame against the exact (height, width, 3) shape fixed at construction; av.VideoFrame.from_ndarray requires a matching bgr24 layout. Any frame of different resolution, channel count, or an accidentally transposed (W, H) array is rejected.
Source
Thrown at src/supervision/_cv2/_video.py:234
self._stream = self._container.add_stream(codec, rate=rate)
self._stream.width = self._width
self._stream.height = self._height
self._stream.pix_fmt = pixel_format
self._opened = True
except Exception as exc:
self._error = exc
self.release()
def isOpened(self) -> bool:
"""Return whether the writer initialized successfully."""
return self._opened
def write(self, frame: npt.NDArray[np.uint8]) -> None:
"""Encode one BGR frame and mux all packets produced by the encoder."""
if not self._opened or self._container is None or self._stream is None:
raise RuntimeError("Video writer is not open") from self._error
if frame.shape != (self._height, self._width, 3):
raise ValueError(
"Video frame must have shape "
f"({self._height}, {self._width}, 3), got {frame.shape}"
)
if frame.dtype != np.uint8:
raise ValueError("Video frames must use uint8 dtype")
video_frame = av.VideoFrame.from_ndarray(
np.ascontiguousarray(frame), format="bgr24"
)
for packet in self._stream.encode(video_frame):
self._container.mux(packet)
def release(self) -> None:
"""Flush delayed encoder packets and close the output container."""
container = self._container
stream = self._stream
self._container = None
self._stream = NoneView on GitHub (pinned to 7f254d9784)
Solutions
- Construct the writer with (height, width) from an actual frame: frame_size=(frame.shape[1], frame.shape[0]) — note OpenCV's VideoWriter takes (width, height).
- Resize every frame to the writer's fixed size before write().
- Ensure frames are 3-channel BGR; convert grayscale with cv2.cvtColor.
Example fix
# before
writer = cv2.VideoWriter('out.mp4', fourcc, fps, (1080, 1920)) # swapped; frames are (1920,1080,3)
# after
writer = cv2.VideoWriter('out.mp4', fourcc, fps, (1920, 1080)) Defensive patterns
Strategy: validation
Validate before calling
h, w = frame.shape[:2] writer = cv2.VideoWriter(path, fourcc, fps, (w, h)) # OpenCV order: (width, height) assert frame.shape == (h, w, 3)
Prevention
- Derive writer frame_size from an actual frame, not from config constants
- Remember VideoWriter takes (width, height) while arrays are (height, width, channels)
- Resize all frames to one fixed resolution before writing
When it happens
Trigger: Passing frames whose shape differs from the constructor's frame_size — e.g. writer created with (1920, 1080) while frames are 1080p after a resize, width/height swapped at construction, or 2D grayscale frames.
Common situations: The classic OpenCV bug of passing (width, height) instead of (height, width) to VideoWriter, annotators that change frame resolution mid-stream, or mixing sources (webcam + file) with one writer.
Related errors
- PyAV video fallback only supports color (3-channel BGR) fram
- Video writer is not open
- Video frames must use uint8 dtype
- addWeighted inputs must have equal shapes
- Mean mask must match the image height and width
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/01943322a7da5443.
Report an issue: GitHub.