roboflow/supervision · error · TypeError
image must be uint8, got {image.dtype}. Convert with image.a
Error message
image must be uint8, got {image.dtype}. Convert with image.astype(np.uint8) before calling show(). What it means
Raised by ImageWindow.show() in supervision.utils.image_window when the input array's dtype is not np.uint8. The Tk-based display path converts the array straight to a Pillow image, which requires 8-bit data; float arrays (common after model preprocessing) would render as garbage or fail inside Pillow, so the dtype is checked up front with an actionable message.
Source
Thrown at src/supervision/utils/image_window.py:108
def show(self, image: npt.NDArray[np.uint8]) -> None:
"""Display a BGR, grayscale, or BGRA frame in the window.
The image is scaled to fit the current window dimensions. Aspect ratio is
preserved unless `keep_aspect_ratio=False`. Resizing the window rescales live.
Args:
image: uint8 numpy array. Accepted shapes:
- ``(H, W)`` — grayscale
- ``(H, W, 3)`` — BGR (OpenCV convention; channels are swapped
to RGB before display)
- ``(H, W, 4)`` — BGRA (channels reordered to RGBA)
Raises:
TypeError: If `image.dtype` is not `uint8`.
ValueError: If `image` is not 2-D or 3-D with 3 or 4 channels.
"""
if image.dtype != np.uint8:
raise TypeError(
f"image must be uint8, got {image.dtype}. "
"Convert with image.astype(np.uint8) before calling show()."
)
self._pil_image = _bgr_to_pil(image)
self._ensure_window()
self._update_display()
self._root.update_idletasks()
self._root.update()
def wait_key(self, delay_ms: int = 0) -> str | None:
"""Wait for a keypress and return its name.
Args:
delay_ms: How long to wait in milliseconds. ``0`` blocks until a
key is pressed. Positive values poll for up to `delay_ms` ms
and return ``None`` if no key arrives in time.
Returns:View on GitHub (pinned to 7f254d9784)
Solutions
- Scale floats back to range then cast: (img * 255).clip(0, 255).astype(np.uint8).
- For arbitrary floats use cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8).
- Convert integer types directly: img.astype(np.uint8) only if values already span 0-255.
- Keep a uint8 copy of the original frame for display alongside the float working copy.
Example fix
// before window.show(frame / 255.0) # float64 -> TypeError // after window.show((frame / 255.0 * 255).clip(0, 255).astype(np.uint8))
Defensive patterns
Strategy: type-guard
Validate before calling
def ensure_uint8(img: np.ndarray) -> np.ndarray:
if img.dtype == np.uint8:
return img
if np.issubdtype(img.dtype, np.floating):
return (img * 255 if img.max() <= 1.0 else img).clip(0, 255).astype(np.uint8)
return img.astype(np.uint8)
window.show(ensure_uint8(image)) Type guard
def is_uint8_image(image: np.ndarray) -> bool:
return image.dtype == np.uint8 Prevention
- Keep an untouched uint8 copy of each frame for display.
- Centralize float-to-uint8 conversion in one helper used before all visualization.
When it happens
Trigger: Calling window.show(image) with a float32/float64 array (e.g. normalized 0-1 images, model outputs, cv2.resize on floats); uint16 medical/scientific imagery; boolean masks.
Common situations: Displaying frames that went through normalization (image / 255.0); annotator outputs assumed to stay uint8 but a preprocessing step cast them; stacking with np.mean producing float; feeding depth maps.
Related errors
- box coordinates must be real-valued
- Expected shape (H,W), (H,W,3), or (H,W,4), got {image.shape}
- Unsupported image type: {type(image)}
- Detection annotation for image {image_path} contains non-int
- Detections class_id must be an integer for Pascal VOC export
AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15).
Data as JSON: /api/errors/6b7a24740f19da1e.
Report an issue: GitHub.