Intervention/image · error · ModifierException

Failed to apply Intervention\Image\Drivers\Gd\Modifiers\Trim

Error message

Failed to apply Intervention\Image\Drivers\Gd\Modifiers\TrimModifier, unable to read trim color from index

What it means

After imagecolorat() returns a color index for a corner pixel, GD's imagecolorsforindex() must translate it into RGBA parts; it raised a ValueError because that index does not exist in the image's color table. This is the signature of a malformed palette image — a PNG or GIF whose palette holds fewer entries than the index stored in its pixel data — since a well-formed image never references an unallocated palette slot.

Source

Thrown at src/Drivers/Gd/Modifiers/TrimModifier.php:135

            new Point($size->width() - 1, 0),
            new Point(0, $size->height() - 1),
            new Point($size->width() - 1, $size->height() - 1),
        ];

        // create an average color to be used in trim operation
        foreach ($cornerPoints as $pos) {
            $cornerColor = imagecolorat($image->core()->native(), $pos->x(), $pos->y());

            if ($cornerColor === false) {
                throw new ModifierException(
                    'Failed to apply ' . self::class . ', unable to determine average color for process',
                );
            }

            try {
                $rgb = imagecolorsforindex($image->core()->native(), $cornerColor);
            } catch (ValueError) {
                throw new ModifierException(
                    'Failed to apply ' . self::class . ', unable to read trim color from index',
                );
            }

            $red += round(round($rgb['red'] / 51) * 51);
            $green += round(round($rgb['green'] / 51) * 51);
            $blue += round(round($rgb['blue'] / 51) * 51);
            $alpha += $rgb['alpha'];
        }

        $red = (int) round($red / 4);
        $green = (int) round($green / 4);
        $blue = (int) round($blue / 4);
        $alpha = (int) round($alpha / 4);

        $color = imagecolorallocatealpha($image->core()->native(), $red, $green, $blue, $alpha);

        if ($color === false) {

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Re-encode the suspect source once through a strict decoder to normalize the palette, then trim the re-encoded data.
  2. Validate uploads with an imagecreatefromstring() round-trip and reject files that fail.
  3. Convert palette images to truecolor with imagepalettetotruecolor() before trimming so no palette lookup is needed.

Example fix

// before
$image = $manager->read('broken-palette.gif')->trim();

// after: normalize a suspect palette image to truecolor PNG, then trim
$gd = imagecreatefromstring(file_get_contents('broken-palette.gif'));
imagepalettetotruecolor($gd);
ob_start();
imagepng($gd);
$image = $manager->read(ob_get_clean())->trim();
Defensive patterns

Strategy: try-catch

Validate before calling

// round-trip decode to reject files with corrupt palettes
$gd = @imagecreatefromstring(file_get_contents($path));
if ($gd === false) {
    throw new RuntimeException('Corrupt or truncated image file');
}

Try / catch

try { $image->trim(); } catch (ModifierException $e) { /* treat as corrupt source: re-encode from binary once, then quarantine */ }

Prevention

When it happens

Trigger: trim() on a palette-based PNG or GIF whose PLTE chunk was truncated, hand-edited, or written by a broken encoder; files that survived a partial upload with intact headers but damaged palette data.

Common situations: User uploads delivered truncated (network cut, wrong Content-Length); images produced by obscure third-party exporter libraries; GIFs re-assembled from frame dumps.

Related errors


AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23). Data as JSON: /api/errors/1852b4e3c52bd362. Report an issue: GitHub.