#1888·thumbor

[Bug] Post-transform filters are skipped for every GIF source, even with USE_GIFSICLE_ENGINE = False

Author: nlemoineCreated Aug 27, 2026Updated Sep 7, 2026

Thumbor Request URL

http://example.com/unsafe/100x100/filters:grayscale()/raw.githubusercontent.com/thumbor/thumbor/master/tests/fixtures/images/animated-one-frame.gif

Expected Behaviour

The filter should apply. The docs tie the filter skip to the gifsicle engine ("WARNING: When using gifsicle engine, filters will be skipped"), and USE_GIFSICLE_ENGINE is False by default, so a stock install should run filters on a GIF like it does on any other format.

Actual Behaviour

Every post-transform filter is silently dropped for any GIF source. The request returns 200 with the unfiltered image. The only value that restores filters is None, which is not a documented value.

Repro with your own fixtures, thumbor 7.7.7. animated-one-frame.gif is the GIF, 256_color_palette.png is the control. sha256 of the returned bytes, first 12 chars, only the config value changes between blocks:

USE_GIFSICLE_ENGINE = False (the default)
  animated-one-frame.gif  plain            3a8f9e271b44
  animated-one-frame.gif  brightness(50)   3a8f9e271b44
  animated-one-frame.gif  grayscale()      3a8f9e271b44
  256_color_palette.png   plain            3a8628c5b679
  256_color_palette.png   brightness(50)   d2edf0cd41d3
  256_color_palette.png   grayscale()      e9aecf1838fa

USE_GIFSICLE_ENGINE = None
  animated-one-frame.gif  plain            3a8f9e271b44
  animated-one-frame.gif  brightness(50)   dbef9265c93b
  animated-one-frame.gif  grayscale()      5259274f5da2

True behaves like False here, which is the documented case.

This also catches upscale(), which declares no phase and so lands in PHASE_POST_TRANSFORM:

fit-in/300x300              USE_GIFSICLE_ENGINE=False   =None
  animated-one-frame.gif    100x100                     300x300
  256_color_palette.png     300x75                      300x75

Two notes.

It is not about animation. animated-one-frame.gif is a single frame, and it gets the same treatment. The gate reads request.extension, which is set from the sniffed source MIME, so any GIF is affected.

There is an old issue in this area, #885, which observed that only the POST_TRANSFORM filters are skipped and treated it as a documentation problem. It was closed for inactivity in 2022 and does not mention that the skip happens with gifsicle off.

I have no fix to propose, I only work at the URL layer against thumbor. What I can say from the outside is that the documented values are False and True, and neither of them gets you filters on a GIF.

Operating System

Official Docker image ghcr.io/thumbor/thumbor:latest (Debian 11 bullseye, thumbor 7.7.7, Pillow 10.4.0), host macOS 15.7.3.

Your thumbor.conf

python
SECURITY_KEY = "dummy-key"
ALLOW_UNSAFE_URL = True
LOADER = "thumbor.loaders.http_loader"
# USE_GIFSICLE_ENGINE left at its False default for the failing case, then set
# to True and to None for the other two blocks. Nothing else is set.