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

Image source must be an instance of Imagick

Error message

Image source must be an instance of Imagick

What it means

NativeObjectDecoder::decode() was called with a value that is not an Imagick object. In normal usage ImageManager::read() routes input through the decoder chain via supports() (which checks instanceof Imagick), so hitting this means the specialized decoder was invoked directly or a custom pipeline bypassed the manager's routing.

Source

Thrown at src/Drivers/Imagick/Decoders/NativeObjectDecoder.php:46

    public function supports(mixed $input): bool
    {
        return $input instanceof Imagick;
    }

    /**
     * {@inheritdoc}
     *
     * @see DecoderInterface::decode()
     *
     * @throws InvalidArgumentException
     * @throws StateException
     * @throws DriverException
     * @throws ImageDecoderException
     */
    public function decode(mixed $input): ImageInterface
    {
        if (!$input instanceof Imagick) {
            throw new InvalidArgumentException('Image source must be an instance of Imagick');
        }

        try {
            $originalMimeType = $input->getImageMimeType();
        } catch (ImagickException $e) {
            throw new ImageDecoderException('Failed to retrieve image media type', previous: $e);
        }

        // For some JPEG formats, the "coalesceImages()" call leads to an image
        // completely filled with background color. The logic behind this is
        // incomprehensible for me; could be an imagick bug.
        try {
            if ($input->getImageFormat() !== 'JPEG') {
                $input = $input->coalesceImages();
            }
        } catch (ImagickException $e) {
            throw new DriverException('Failed to coalesce image', previous: $e);
        }

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Use ImageManager::read($input) instead of calling the decoder directly - it routes Imagick objects to this decoder automatically
  2. If calling decode() directly, guard with instanceof Imagick or the decoder's supports() method first
  3. For GD-native objects (GdImage), construct the manager with the GD driver and read through it

Example fix

// before
$decoder = new NativeObjectDecoder($driver);
$image = $decoder->decode($gdImage); // GdImage passed to Imagick decoder

// after: route through the manager, which dispatches by type via supports()
$gdManager = new ImageManager(['driver' => 'gd']);
$image = $gdManager->read($gdImage); // or for Imagick: $manager->read($imagick)
Defensive patterns

Strategy: type-guard

Type guard

function isImagickObject(mixed $value): bool
{
    return $value instanceof \Imagick;
}

Prevention

When it happens

Trigger: Calling (new NativeObjectDecoder($driver))->decode($value) manually with a GdImage, ImagickPixel, string or null; custom decoder chains assembled by hand; code ported from the GD driver where the native object type is GdImage.

Common situations: Porting driver-specific code from GD to Imagick; wrapper classes that hold a 'native' object of mixed driver origin and pass it to the wrong decoder.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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