{"record":{"id":"9bc60a895e54684a","repo":"roboflow/supervision","slug":"video-frames-must-use-uint8-dtype","errorCode":null,"errorMessage":"Video frames must use uint8 dtype","messagePattern":"Video frames must use uint8 dtype","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/_cv2/_video.py","lineNumber":239,"sourceCode":"        except Exception as exc:\n            self._error = exc\n            self.release()\n\n    def isOpened(self) -> bool:\n        \"\"\"Return whether the writer initialized successfully.\"\"\"\n        return self._opened\n\n    def write(self, frame: npt.NDArray[np.uint8]) -> None:\n        \"\"\"Encode one BGR frame and mux all packets produced by the encoder.\"\"\"\n        if not self._opened or self._container is None or self._stream is None:\n            raise RuntimeError(\"Video writer is not open\") from self._error\n        if frame.shape != (self._height, self._width, 3):\n            raise ValueError(\n                \"Video frame must have shape \"\n                f\"({self._height}, {self._width}, 3), got {frame.shape}\"\n            )\n        if frame.dtype != np.uint8:\n            raise ValueError(\"Video frames must use uint8 dtype\")\n\n        video_frame = av.VideoFrame.from_ndarray(\n            np.ascontiguousarray(frame), format=\"bgr24\"\n        )\n        for packet in self._stream.encode(video_frame):\n            self._container.mux(packet)\n\n    def release(self) -> None:\n        \"\"\"Flush delayed encoder packets and close the output container.\"\"\"\n        container = self._container\n        stream = self._stream\n        self._container = None\n        self._stream = None\n        self._opened = False\n        if container is None:\n            return\n        try:\n            if stream is not None:","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/_cv2/_video.py#L221-L257","documentation":"The PyAV writer wraps frames with av.VideoFrame.from_ndarray(..., format='bgr24'), which requires uint8 data. Frames in float32/float64 (normalized 0-1 images, model outputs) or uint16 are rejected before encoding.","triggerScenarios":"Writing float arrays such as normalized model outputs, occupancy heat maps, or images processed in float precision without converting back to uint8.","commonSituations":"Pipelines that normalize frames for inference and forget to de-normalize; heat-map visualizations computed in float; mixing annotated float arrays from matplotlib-like operations. Real OpenCV also misbehaves with non-uint8, but the fallback fails loudly.","solutions":["Convert before writing: frame_u8 = np.clip(frame * 255, 0, 255).astype(np.uint8).","If already in 0-255 floats: frame_u8 = frame.astype(np.uint8).","Keep a single uint8 annotation canvas instead of converting model tensors directly."],"exampleFix":"# before\nwriter.write(heatmap_float)  # float64 in [0, 1]\n\n# after\nframe_u8 = (np.clip(heatmap_float, 0, 1) * 255).astype(np.uint8)\nwriter.write(np.stack([frame_u8]*3, axis=-1))","handlingStrategy":"validation","validationCode":"if frame.dtype != np.uint8:\n    frame = np.clip(frame, 0, 255).astype(np.uint8) if frame.max() > 1 else (np.clip(frame, 0, 1) * 255).astype(np.uint8)\nwriter.write(frame)","typeGuard":"def is_writable_frame(frame: np.ndarray) -> bool:\n    return frame.dtype == np.uint8 and frame.ndim == 3 and frame.shape[2] == 3","tryCatchPattern":null,"preventionTips":["Convert float frames to uint8 before write","De-normalize [0,1] model outputs with *255","Keep annotation canvases uint8 end-to-end"],"tags":["opencv-fallback","pyav","video-writer","dtype","uint8"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}