Quick fix

Reinstall Pillow for the interpreter you are running: python -m pip install --force-reinstall --upgrade pillow. Then check that python -c "import PIL; print(PIL.__file__)" points into that interpreter's site-packages, not into your project folder. For Lambda, Docker or a copied site-packages, install Pillow on (or for) the platform where the code runs.

The error

To reproduce it, we put a copy of Pillow next to the script with the compiled extension missing, like a vendored copy made on another machine:

app.py
from PIL import Image
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
  File "/home/you/project/PIL/Image.py", line 95, in <module>
    from . import _imaging as core
ImportError: cannot import name '_imaging' from 'PIL' (/home/you/project/PIL/__init__.py)

Notice the path in the message: from 'PIL' (/home/you/project/PIL/__init__.py). It tells you which PIL Python found. If that is not inside your environment's site-packages, a local folder is shadowing the real install:

which_pil.py
import PIL
print(PIL.__file__)
print(PIL.__version__)
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
/home/you/project/PIL/__init__.py
12.3.0

Even PIL.__version__ works, because it does not need the compiled part. Delete or rename the stray folder (often a PIL directory copied in by hand, or left by a build tool) and the installed Pillow is used again.

The _imaging extension was built for another version of Pillow

Pillow checks that its Python files and its compiled core come from the same release. They stop matching when an upgrade is interrupted, when two installs overlap in one folder, or when pip and conda both manage Pillow in the same environment. We faked a half-upgraded install by editing the version file:

app.py
from PIL import Image
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
ImportError: The _imaging extension was built for another version of Pillow or PIL:
Core version: 12.3.0
Pillow version: 11.0.0

Reinstall cleanly: python -m pip uninstall -y pillow (repeat until it says Pillow is not installed), then python -m pip install pillow. In a conda environment, use conda install pillow for both steps instead of mixing the two tools.

libtiff-…so: cannot open shared object file (Lambda, Docker, zipped deployments)

On Linux, the Pillow wheel keeps the libraries it bundles (libjpeg, libtiff, libwebp…) in a separate pillow.libs folder beside PIL. Copy only PIL, as hand-made AWS Lambda layers and some Dockerfiles do, and the core cannot load:

handler.py
from PIL import Image
Tested on ✓ Linux (Linux-specific example)
Output
ImportError: libtiff-fc87e79d.so.6.2.0: cannot open shared object file: No such file or directory

The same happens when the package was installed on macOS or Windows and uploaded to Linux. Build the deployment package with the target platform's wheel and ship the whole folder:

Terminal
pip install pillow --platform manylinux_2_28_x86_64 --only-binary=:all: --python-version 3.13 --target package/

Use manylinux_2_28_aarch64 for ARM (Graviton) functions, and the Python version of your runtime. The manylinux2014 tag found in many older guides no longer works: we checked, and pip finds no Pillow 12.3 wheel for it, because current Pillow wheels target glibc 2.28 and newer.

Windows: DLL load failed while importing _imaging

This is the Windows form of the same failure. Typical causes, in the order we would check them:

_imagingft: fonts fail, everything else works

_imagingft is the separate extension that wraps FreeType. If only it is missing or broken, you can open, edit and save images, but text with TrueType fonts fails, and only when you load a font:

label.py
from PIL import Image, ImageDraw, ImageFont

print("imported fine")
font = ImageFont.truetype("DejaVuSans.ttf", 40)
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
ImportError: cannot import name '_imagingft' from 'PIL' (/home/you/project/PIL/__init__.py). Did you mean: '_imaging'?

Older Pillow versions phrased this as The _imagingft C module is not installed. With official wheels it does not happen; it means Pillow was built from source without the FreeType headers. Install a wheel (upgrade pip first, so it can find one for your platform), or install FreeType's development package before building.

decoder jpeg not available, and checking what your Pillow supports

OSError: decoder jpeg not available (or zip, for PNG) comes from the same kind of source build: Pillow compiled without libjpeg or zlib. The official wheels include them. To see what an installation supports:

check_features.py
from PIL import features

for name in ["jpg", "zlib", "libtiff", "freetype2", "webp", "avif", "littlecms2", "raqm"]:
    print(f"{name:<11}", features.check(name), features.version(name) or "")
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
jpg         True 6.2
zlib        True 1.3
libtiff     True 4.7.1
freetype2   True 2.14.3
webp        True 1.6.0
avif        True 1.4.2
littlecms2  True 2.19
raqm        True 0.10.5

python -m PIL.report prints the full report, including the Python and Pillow paths it is using, which is the first thing to paste into a bug report. Run it from a folder without a stray PIL directory, or it reports on that copy instead.

The outputs and images on this page are the real results of running every example with Pillow 12.3.0 on Python 3.13 (Linux) on 2026-10-15. Every example is also re-run automatically on macOS (Darwin 25.6.0, Pillow 12.3.0), Linux (Linux 6.17.0-1022-azure, Pillow 12.3.0), Windows (Windows 2025Server, Pillow 12.3.0); the line under each example shows the result per operating system. The DejaVu Sans font files sit next to each script so font examples behave the same everywhere. Sample photos: NASA/Sam Lott, public domain. Spotted something wrong? Tell us.