Intervention/image · error · Intervention\Image\Exceptions\ImageDecoderException

Failed to decode unsupported image format from binary data

Error message

Failed to decode unsupported image format from binary data

What it means

Thrown by BinaryImageDecoder::decode() when new Imagick + readImageBlob($input) throws — the byte string is not data ImageMagick can parse as an image. The original ImagickException is swallowed (no previous), so the exact native reason is not visible. This is the workhorse 'not an image' error for binary input on the Imagick driver.

Source

Thrown at src/Drivers/Imagick/Decoders/BinaryImageDecoder.php:60

    public function decode(mixed $input): ImageInterface
    {
        if (!is_string($input) && !$input instanceof Stringable) {
            throw new InvalidArgumentException(
                'Image source must be binary data of type string or instance of ' . Stringable::class,
            );
        }

        $input = (string) $input;

        if ($input === '') {
            throw new InvalidArgumentException('Unable to decode binary data from empty string');
        }

        try {
            $imagick = new Imagick();
            $imagick->readImageBlob($input);
        } catch (ImagickException) {
            throw new ImageDecoderException('Failed to decode unsupported image format from binary data');
        }

        // decode image
        $image = parent::decode($imagick);

        // get media type enum from string media type
        $format = Format::tryCreate($image->origin()->mediaType());

        // extract exif data for appropriate formats
        if (in_array($format, [Format::JPEG, Format::TIFF])) {
            $image->setExif($this->extractExifData($input));
        }

        return $image;
    }
}

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Verify the bytes with a signature sniff before calling read() (finfo, getimagesize, or manual magic bytes)
  2. Confirm the source actually transferred fully (check download size vs Content-Length)
  3. Run convert -list format on the server and install delegates for the formats you accept
  4. Catch ImageDecoderException around read() and reject/log the source

Example fix

// before: trusting remote bytes
$image = $manager->read($http->get($url)->getBody());

// after: sniff the format first
$bytes = (string) $http->get($url)->getBody();
$mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($bytes);
if (!str_starts_with($mime, 'image/')) {
    throw new InvalidArgumentException("Source at {$url} is {$mime}, not an image");
}
$image = $manager->read($bytes);
Defensive patterns

Strategy: try-catch

Validate before calling

$mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($bytes);
if (!str_starts_with((string) $mime, 'image/')) {
    throw new InvalidArgumentException("refusing non-image payload ({$mime})");
}
$image = $manager->read($bytes);

Try / catch

use Intervention\Image\Exceptions\ImageDecoderException;

try {
    $image = $manager->read($bytes);
} catch (ImageDecoderException $e) {
    Log::notice('undecodable image rejected', ['bytes' => strlen($bytes)]);
    return response()->json(['error' => 'image could not be decoded'], 422);
}

Prevention

When it happens

Trigger: $manager->read($binary) where $binary is corrupt (truncated download, bit-flipped upload), a non-image file renamed to .png, HTML/XML error output from a misconfigured URL, or a real image in a format the installed ImageMagick cannot decode (AVIF/HEIC/WebP without delegates, CMYK variants on old builds).

Common situations: Scraping pipelines capturing 404 pages as 'images'; partial uploads with Content-Length mismatches; deployments where the imagick extension's underlying libmagick lacks delegates present on dev machines; SVG payloads when rsvg is missing.

Understand the failure class

Related errors


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