Intervention/image · error · ImageDecoderException
Result must be instance of {ImageInterface::class}
Error message
Result must be instance of {ImageInterface::class} What it means
The image decoder chain completed but the object it produced is not an ImageInterface. The driver validates the handler's result before returning it. Built-in decoders always return images, so this is a contract violation of a custom decoder plugged into the chain.
Source
Thrown at src/Drivers/AbstractDriver.php:70
* @throws DriverException
*/
public function decodeImage(mixed $input, ?array $decoders = null): ImageInterface
{
$decoders = $decoders === null ? InputHandler::IMAGE_DECODERS : $decoders;
if (count($decoders) === 0) {
throw new InvalidArgumentException('No decoders in array');
}
try {
$result = InputHandler::usingDecoders($decoders, $this)->handle($input);
} catch (NotSupportedException) {
$type = is_object($input) ? $input::class : gettype($input);
throw new InvalidArgumentException('Unsupported image source type "' . $type . '"');
}
if (!$result instanceof ImageInterface) {
throw new ImageDecoderException('Result must be instance of ' . ImageInterface::class);
}
return $result;
}
/**
* {@inheritdoc}
*
* @see DriverInterface::decodeColor()
*
* @throws InvalidArgumentException
* @throws ColorDecoderException
* @throws DriverException
*/
public function decodeColor(mixed $input, ?array $decoders = null): ColorInterface
{
$decoders = $decoders === null ? InputHandler::COLOR_DECODERS : $decoders;
View on GitHub (pinned to 5598b9e397)
Solutions
- Make the custom decoder return an ImageInterface - typically by wrapping another decoder's result or building the image through the driver
- Delegate the heavy lifting to an existing decoder (e.g. BinaryDecoder) and post-process the returned image
Example fix
// before
class S3Decoder implements DecoderInterface
{
public function decode(mixed $input): mixed
{
return $this->s3->get($input); // raw bytes
}
}
// after
public function decode(mixed $input): ImageInterface
{
return $this->driver->decodeImage($this->s3->get($input));
} Defensive patterns
Strategy: type-guard
Type guard
function isValidDecoder(mixed $decoder): bool
{
return $decoder instanceof \Intervention\Image\Interfaces\DecoderInterface;
} Try / catch
try {
$image = $driver->decodeImage($input, [new MyDecoder()]);
} catch (ImageDecoderException $e) {
// custom decoder broke the contract - fix its return type
} Prevention
- Type custom decoders' return as ImageInterface so PHP enforces the contract
- Delegate to built-in decoders inside custom ones
When it happens
Trigger: A custom DecoderInterface implementation whose decode() returns a string, array, null, or a DTO instead of an ImageInterface, invoked via $driver->decodeImage($input, [new MyDecoder()]).
Common situations: Custom decoders for app-specific sources (S3 streams, database blobs, remote URLs) that return raw data instead of delegating to an existing decoder and returning the parsed image.
Related errors
- Result must be instance of {ColorInterface::class}
- No decoders in array
- Invalid $limit value. Must be int<1, max>
- Call to undefined method Intervention\Image\Image::{name}()
- Hex color has an incorrect length
AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23).
Data as JSON: /api/errors/20c1ac3a1599d080.
Report an issue: GitHub.