OSError: image file is truncated (N bytes not processed)
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
Set it once, before you open anything. Pillow then decodes as much as it can and leaves the rest grey.
Truncated files nearly always come from one of four places: a download that was interrupted, a file copied while still being written, an upload cut short by a timeout, or storage that ran out of space mid write.
If you are fetching images, check the response is complete before you decode:
import requests
from io import BytesIO
from PIL import Image
r = requests.get(url, timeout=20)
r.raise_for_status()
im = Image.open(BytesIO(r.content))
im.load()
The load() call forces the decode to happen there, where you can catch it, rather than later somewhere confusing.
from PIL import Image
try:
with Image.open(path) as im:
im.verify()
except Exception as problem:
print(path, "is damaged:", problem)
verify checks the structure without decoding the pixels. The image object cannot be used afterwards, so open it again to work with it. See the ImageFile module.
The PIL to Pillow converter finds most of these automatically, and the other error pages cover the rest.