roboflow/supervision · error · TypeError

`image` must be a numpy.ndarray or PIL.Image.Image. Received

Error message

`image` must be a numpy.ndarray or PIL.Image.Image. Received {type(image)}

What it means

Raised by `sv.crop_image` when the `image` argument is neither a `numpy.ndarray` nor a `PIL.Image.Image`. The function dispatches on these two types (each has a different crop path) and has no behavior for anything else, so it fails fast with a TypeError naming the received type.

Source

Thrown at src/supervision/utils/image.py:223

    x_min, y_min, x_max, y_max = xyxy_arr.flatten()

    if isinstance(image, np.ndarray):
        height, width = image.shape[:2]
        x_min = int(np.clip(x_min, 0, width))
        y_min = int(np.clip(y_min, 0, height))
        x_max = int(np.clip(x_max, 0, width))
        y_max = int(np.clip(y_max, 0, height))
        return image[y_min:y_max, x_min:x_max]

    if isinstance(image, Image.Image):
        width, height = image.size
        x_min = int(np.clip(x_min, 0, width))
        y_min = int(np.clip(y_min, 0, height))
        x_max = int(np.clip(x_max, 0, width))
        y_max = int(np.clip(y_max, 0, height))
        return image.crop((float(x_min), float(y_min), float(x_max), float(y_max)))

    raise TypeError(
        f"`image` must be a numpy.ndarray or PIL.Image.Image. Received {type(image)}"
    )


@ensure_cv2_image_for_standalone_function
def scale_image(image: ImageType, scale_factor: float) -> ImageType:
    """
    Scale image by given factor. Scale factor > 1.0 zooms in, < 1.0 zooms out.

    Args:
        image: The image to scale.
        scale_factor: Factor by which to scale the image.

    Returns:
        Scaled image matching input
            type.

    Raises:

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Convert tensors: `image.detach().cpu().numpy()` before cropping.
  2. Load paths first: `cv2.imread(path)` or `PIL.Image.open(path)`.
  3. Decode bytes with `cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR)`.

Example fix

# before
crop = sv.crop_image(image='/data/frame.jpg', xyxy=box)
# after
import cv2
crop = sv.crop_image(image=cv2.imread('/data/frame.jpg'), xyxy=box)
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(image, (np.ndarray, Image.Image)), type(image)

Type guard

from PIL import Image
import numpy as np

def is_image(x: Any) -> bool:
    return isinstance(x, (np.ndarray, Image.Image))

Try / catch

try:
    crop = sv.crop_image(image, xyxy)
except TypeError as e:
    raise TypeError(f'load the image first: {e}') from e

Prevention

When it happens

Trigger: Passing a file path string, a `torch.Tensor`, a `cv2.VideoCapture` frame proxy, or bytes to `sv.crop_image(image=..., xyxy=...)`.

Common situations: Loading with PIL/opencv elsewhere but passing the path by mistake; deep-learning pipelines handing raw tensors to a utility that expects numpy; reading bytes from an HTTP response without decoding first via `sv.load_image_from_url`/`cv2.imdecode`.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/58e2ec755546ff60. Report an issue: GitHub.