Intervention/image · error · InvalidArgumentException

Image source must be of type GdImage

Error message

Image source must be of type GdImage

What it means

Contract violation of NativeObjectDecoder::decode: the input is not a GdImage instance. This GD-driver decoder accepts only native GD resources/objects, so anything else (string, resource, Imagick object, null) triggers an InvalidArgumentException immediately. In the manager's auto-routing supports() filters for GdImage, so this fires mainly on direct decoder calls or miswired custom chains.

Source

Thrown at src/Drivers/Gd/Decoders/NativeObjectDecoder.php:43

     */
    public function supports(mixed $input): bool
    {
        return $input instanceof GdImage;
    }

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

        if (!imageistruecolor($input)) {
            $result = imagepalettetotruecolor($input);
            if ($result === false) {
                throw new DriverException('Failed to convert image to true color');
            }
        }

        imagesavealpha($input, true);

        // build image instance
        return new Image(
            $this->driver(),
            new Core([
                new Frame($input),
            ]),
        );

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Guard the value: $input instanceof GdImage before invoking decode; check for false after any imagecreate* call
  2. Let ImageManager::read() do the dispatch — pass binary/paths and let it route to the right decoder
  3. Convert foreign objects first: Imagick images can be re-encoded to PNG bytes and re-read; older resources are automatically GdImage on PHP >= 8
  4. Type the upstream API as GdImage instead of mixed so violations surface at the caller

Example fix

// before
$gd = @imagecreatetruecolor(100, 100); // returns GdImage|false
$decoder = new NativeObjectDecoder();
$image = $decoder->decode($gd); // $gd may be false
// InvalidArgumentException: Image source must be of type GdImage

// after
$gd = imagecreatetruecolor(100, 100);
if ($gd === false) {
    throw new RuntimeException('GD failed to allocate the canvas');
}
$image = $decoder->decode($gd);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!$input instanceof \GdImage) {
    throw new InvalidArgumentException('Expected GdImage, got ' . get_debug_type($input));
}

Type guard

/**
 * @param mixed $input
 */
function isGdImage(mixed $input): bool
{
    return $input instanceof \GdImage;
}

Prevention

When it happens

Trigger: Calling the native decoder (or a pipeline built on it) with an Imagick object, a file-path string, a GD resource from older PHP (PHP < 8 resources vs GdImage), or null; passing the result of a function that returns GdImage|false without checking the false branch.

Common situations: Migrating pre-PHP-8 code where imagecreate* returned resources; mixed-driver codebases where Imagick and GD objects flow through the same variable; false from a failed imagecreatetruecolor(color-mode) leaking in; unit tests instantiating decoders directly.

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/307269c5e90677b7. Report an issue: GitHub.