huggingface/transformers · error · ValueError

The image to be converted to a PIL image contains values out

Error message

The image to be converted to a PIL image contains values outside the range [0, 255], got [{image.min()}, {image.max()}] which cannot be converted to uint8.

What it means

_rescale_for_pil_conversion decides whether an image needs 0-1 -> 0-255 rescaling before uint8 PIL conversion. If every value is integral (np.allclose to int cast) but some fall outside [0, 255], PIL cannot store them as uint8, so it raises. This is a data-range sanity guard inside to_pil_image/resize paths.

Source

Thrown at src/transformers/image_transforms.py:140

    rescaled_image = rescaled_image.astype(dtype)  # Finally downcast to the desired dtype at the end

    return rescaled_image


def _rescale_for_pil_conversion(image):
    """
    Detects whether or not the image needs to be rescaled before being converted to a PIL image.

    The assumption is that if the image is of type `np.float` and all values are between 0 and 1, it needs to be
    rescaled.
    """
    if image.dtype == np.uint8:
        do_rescale = False
    elif np.allclose(image, image.astype(int)):
        if np.all(image >= 0) and np.all(image <= 255):
            do_rescale = False
        else:
            raise ValueError(
                "The image to be converted to a PIL image contains values outside the range [0, 255], "
                f"got [{image.min()}, {image.max()}] which cannot be converted to uint8."
            )
    elif np.all(image >= 0) and np.all(image <= 1):
        do_rescale = True
    else:
        raise ValueError(
            "The image to be converted to a PIL image contains values outside the range [0, 1], "
            f"got [{image.min()}, {image.max()}] which cannot be converted to uint8."
        )
    return do_rescale


def to_pil_image(
    image: Union[np.ndarray, "PIL.Image.Image", "torch.Tensor"],
    do_rescale: bool | None = None,
    image_mode: str | None = None,
    input_data_format: str | ChannelDimension | None = None,

View on GitHub (pinned to a597f97485)

Solutions

  1. Clip the image to the valid range before conversion: image = np.clip(image, 0, 255).
  2. Check whether you already rescaled; pass do_rescale=False to to_pil_image if values are already 0-255.
  3. Undo any normalization (multiply back by std, add mean) before visualizing model-preprocessed images.

Example fix

# before
img = np.clip(img, 0, 1) * 255 + 100  # integral values > 255
pil = to_pil_image(img)

# after
img = np.clip(img, 0, 255).astype(np.uint8)
pil = to_pil_image(img, do_rescale=False)
Defensive patterns

Strategy: validation

Validate before calling

if image.dtype != np.uint8:
    if image.min() < 0 or image.max() > 255:
        image = np.clip(image, 0, 255)
# or explicitly: to_pil_image(image, do_rescale=False) when already 0-255

Type guard

def is_pil_convertible(img) -> bool:
    if img.dtype == np.uint8:
        return True
    return bool(np.all(img >= 0) and (np.all(img <= 1) or (np.allclose(img, img.astype(int)) and np.all(img <= 255))))

Prevention

When it happens

Trigger: Calling to_pil_image on an already-uint8-range-overflowed array, e.g. values like 300 or -5 that are whole numbers; or rescaling twice so values are 0-510 but still integral; float images with integer-valued pixels above 255.

Common situations: Double rescaling (applying rescale(image, 255) manually and then to_pil_image rescales again), normalizing before visualization, or arithmetic on images (addition/subtraction) pushing values out of range.

Related errors


AI-assisted analysis of huggingface/transformers@a597f97485 (2026-08-14). Data as JSON: /api/errors/11f33b1823a618af. Report an issue: GitHub.