matplotlib/matplotlib · error · RuntimeError

Unknown image mode

Error message

Unknown image mode

What it means

pil_to_array handles Pillow modes RGBA/RGBX/RGB/L directly and the I;16* family via raw byte swapping; every other mode must be convertible via pilImage.convert('RGBA'). When that conversion itself raises ValueError (exotic, corrupt, or unsupported pixel formats), matplotlib re-raises it as RuntimeError('Unknown image mode') during plt.imread.

Source

Thrown at lib/matplotlib/image.py:1793

        - (M, N, 3) for RGB images.
        - (M, N, 4) for RGBA images.
    """
    if pilImage.mode in ['RGBA', 'RGBX', 'RGB', 'L']:
        # return MxNx4 RGBA, MxNx3 RBA, or MxN luminance array
        return np.asarray(pilImage)
    elif pilImage.mode.startswith('I;16'):
        # return MxN luminance array of uint16
        raw = pilImage.tobytes('raw', pilImage.mode)
        if pilImage.mode.endswith('B'):
            x = np.frombuffer(raw, '>u2')
        else:
            x = np.frombuffer(raw, '<u2')
        return x.reshape(pilImage.size[::-1]).astype('=u2')
    else:  # try to convert to an rgba image
        try:
            pilImage = pilImage.convert('RGBA')
        except ValueError as err:
            raise RuntimeError('Unknown image mode') from err
        return np.asarray(pilImage)  # return MxNx4 RGBA array


def _pil_png_to_float_array(pil_png):
    """Convert a PIL `PNGImageFile` to a 0-1 float array."""
    # Unlike pil_to_array this converts to 0-1 float32s for backcompat with the
    # old libpng-based loader.
    # The supported rawmodes are from PIL.PngImagePlugin._MODES.  When
    # mode == "RGB(A)", the 16-bit raw data has already been coarsened to 8-bit
    # by Pillow.
    mode = pil_png.mode
    rawmode = pil_png.png.im_rawmode
    if rawmode == "1":  # Grayscale.
        return np.asarray(pil_png, np.float32)
    if rawmode == "L;2":  # Grayscale.
        return np.divide(pil_png, 2**2 - 1, dtype=np.float32)
    if rawmode == "L;4":  # Grayscale.
        return np.divide(pil_png, 2**4 - 1, dtype=np.float32)

View on GitHub (pinned to b379c1b69e)

Solutions

  1. Pre-open and normalize with Pillow yourself: arr = np.asarray(PIL.Image.open(path).convert('RGB')) before handing data to matplotlib.
  2. Catch the RuntimeError and retry with an explicit convert(), logging the offending file's mode for triage.
  3. Verify file integrity (PIL.Image.open(...).verify()) and re-download corrupt transfers.

Example fix

# before
arr = plt.imread('scan.dat.png')  # RuntimeError: Unknown image mode

# after
import numpy as np, PIL.Image
with PIL.Image.open('scan.dat.png') as im:
    arr = np.asarray(im.convert('RGB'))
Defensive patterns

Strategy: try-catch

Validate before calling

import PIL.Image

with PIL.Image.open(path) as im:
    if im.mode not in {'RGBA', 'RGBX', 'RGB', 'L'} and not im.mode.startswith('I;16'):
        im = im.convert('RGBA')  # normalize before imread/matplotlib
arr = plt.imread(path)

Try / catch

try:
    arr = plt.imread(path)
except RuntimeError as err:
    if 'Unknown image mode' not in str(err):
        raise
    import numpy as np, PIL.Image
    with PIL.Image.open(path) as im:
        arr = np.asarray(im.convert('RGB'))

Prevention

When it happens

Trigger: plt.imread on an image whose Pillow mode cannot convert to RGBA — e.g. some CMYK/palette variants with broken profiles, 1-bit or unusual bit-depth files depending on the Pillow version, or truncated/corrupt downloads (partial file saved from a failed transfer).

Common situations: Bulk-loading user-uploaded or scraped images where formats are uncontrolled; Pillow major-version upgrades changing supported modes; reading files whose extension lies about the actual format.

Related errors


AI-assisted analysis of matplotlib/matplotlib@b379c1b69e (2026-08-21). Data as JSON: /api/errors/d710e17d2b238da5. Report an issue: GitHub.