Quick fix

Replace Image.ANTIALIAS with Image.LANCZOS. It is the same resampling filter, and Image.LANCZOS works on every Pillow release from 2.7 (2015) to 12.3.0, so the change is safe whichever version your users have installed.

What the error looks like

We ran this pre-2023 snippet on Pillow 12.3.0:

resize_old.py
from PIL import Image

img = Image.open("photo.jpg")
small = img.resize((400, 267), Image.ANTIALIAS)
Tested on ✓ Linux ✓ Windows ✓ macOS
Traceback (Pillow 12.3.0)
Traceback (most recent call last):
  File "example.py", line 4, in <module>
    small = img.resize((400, 267), Image.ANTIALIAS)
                                   ^^^^^^^^^^^^^^^
AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'

The same thing happens with Image.LINEAR and Image.CUBIC, which were removed in the same release.

Why ANTIALIAS was removed

The name is historical. Early PIL had one high-quality, convolution-based downscaling filter and called it ANTIALIAS. In Pillow 2.7.0 the bilinear and bicubic filters were rewritten to use the same convolution approach, so "antialias" no longer described anything special, and the filter got its proper name, LANCZOS. ANTIALIAS stayed on as an alias for years before it was removed.

Pillow versionWhat changed
2.7.0 (2015)Image.LANCZOS added; ANTIALIAS kept as an alias.
9.1.0 (2022)Image.Resampling enum added. ANTIALIAS, LINEAR, CUBIC (and, briefly, the other constants) deprecated with warnings.
9.4.0 (2023)Deprecation reversed for NEAREST, BILINEAR, BICUBIC, LANCZOS and friends: they are permanent. ANTIALIAS, LINEAR and CUBIC stay deprecated.
10.0.0 (1 July 2023)ANTIALIAS, LINEAR and CUBIC removed. Old code now raises AttributeError.

One consequence that many tutorials still get wrong: you do not need Image.Resampling.LANCZOS. The short constants were un-deprecated in 9.4.0, so Image.LANCZOS is not going away. The two spellings are the same filter value:

check_names.py
from PIL import Image

# Image.LANCZOS is a plain int; Image.Resampling.LANCZOS is an IntEnum member.
# They compare equal, and every Pillow function accepts either one.
print(repr(Image.LANCZOS), repr(Image.Resampling.LANCZOS))
print(Image.LANCZOS == Image.Resampling.LANCZOS)
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
1 <Resampling.LANCZOS: 1>
True

Fix your own code

Swap the constant. Output pixels are identical to what ANTIALIAS produced:

resize.py
from PIL import Image

img = Image.open("photo.jpg")
small = img.resize((400, 267), Image.LANCZOS)
small.save("photo_small.jpg", quality=90)
print(small.size)
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
(400, 267)

The same applies anywhere a resample argument is accepted, such as thumbnail(), rotate() and transform():

thumbnail.py
from PIL import Image

img = Image.open("photo.jpg")
img.thumbnail((400, 400), Image.LANCZOS)   # was: Image.ANTIALIAS
print(img.size)
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
(400, 267)

Every removed name and its replacement

Removed in 10.0Use insteadEnum form (optional)
Image.ANTIALIASImage.LANCZOSImage.Resampling.LANCZOS
Image.LINEARImage.BILINEARImage.Resampling.BILINEAR
Image.CUBICImage.BICUBICImage.Resampling.BICUBIC

Find every use in a project

Run this from your project root. It lists each file and line that still uses a removed name:

terminal
grep -rnE "Image\.(ANTIALIAS|LINEAR|CUBIC)\b" --include="*.py" .
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
./app/views.py:2:IMG_FILTER = Image.CUBIC
./app/utils/images.py:4:    return img.resize((64, 64), Image.ANTIALIAS)

When the error comes from a library you didn't write

If the traceback ends inside site-packages/, the old constant is in a dependency. In order of preference:

  1. Upgrade the library. Most maintained projects fixed this in 2023. Check its changelog for "Pillow 10".
  2. Add a compatibility shim that restores the old names before the library is imported. This is a stop-gap for unmaintained code, not a long-term fix:
compat_shim.py
from PIL import Image

# Put this before importing the library that still uses the old names.
for old, new in {"ANTIALIAS": "LANCZOS", "LINEAR": "BILINEAR", "CUBIC": "BICUBIC"}.items():
    if not hasattr(Image, old):
        setattr(Image, old, getattr(Image, new))

# import some_old_library   # now finds Image.ANTIALIAS again
print(Image.ANTIALIAS is Image.LANCZOS)
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
True

Why not just pin Pillow<10? Two reasons. First, you would miss three years of security fixes. Second, it often does not install: Pillow 9.5.0 only published wheels up to Python 3.11. On Python 3.12 or 3.13, pip install "Pillow<10" finds no compatible wheel and tries to compile Pillow from source, which fails on most machines without a C compiler and image library headers. We checked: on Python 3.13 the oldest Pillow pip will install from a wheel is 10.4.0.

Does LANCZOS still give the best quality?

For downscaling photos, Lanczos is the sharpest of Pillow's filters, and it is what ANTIALIAS always meant. Here is a 1200 px "zone plate" (rings that get finer towards the edges) shrunk to 300 px with each filter. Nearest-neighbour invents dozens of false ring centres: that is aliasing. Bilinear leaves faint ghost rings, bicubic fewer, and Lanczos keeps the real rings in the middle crisp while suppressing almost all of the false detail:

A zone plate downscaled with NEAREST, BILINEAR, BICUBIC and LANCZOS filters; NEAREST shows many false ring patterns
Real output of the script below: a 1200 px zone plate downscaled to 300 px with NEAREST, BILINEAR, BICUBIC and LANCZOS.
compare_filters.py
from PIL import Image, ImageDraw, ImageFont

src = Image.open("rings.png")              # 1200x1200 zone plate
font = ImageFont.load_default(size=22)
names = ["NEAREST", "BILINEAR", "BICUBIC", "LANCZOS"]
sheet = Image.new("L", (4 * 300, 340), 255)

for i, name in enumerate(names):
    small = src.resize((300, 300), getattr(Image, name))
    sheet.paste(small, (i * 300, 0))
    ImageDraw.Draw(sheet).text((i * 300 + 150, 320), name, fill=0, font=font, anchor="mm")

sheet.save("filters.png")
Tested on ✓ Linux ✓ Windows ✓ macOS

If you never passed a filter at all, resize() already defaults to BICUBIC, and thumbnail() uses BICUBIC with a fast reducing_gap pre-shrink. Both are good defaults; pass Image.LANCZOS only when you want the extra sharpness.

Check which Pillow you have

terminal
python -c "import PIL; print(PIL.__version__)"
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
12.3.0

Anything 10.0 or newer has no ANTIALIAS. If the version printed is not the one you expected, you may be running a different interpreter than the one you installed into; see No module named 'PIL' for how to check.

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.