{"record":{"id":"20c1ac3a1599d080","repo":"Intervention/image","slug":"result-must-be-instance-of-imageinterface-class","errorCode":null,"errorMessage":"Result must be instance of {ImageInterface::class}","messagePattern":"Result must be instance of (.+?)","errorType":"exception","errorClass":"ImageDecoderException","httpStatus":null,"severity":"error","filePath":"src/Drivers/AbstractDriver.php","lineNumber":70,"sourceCode":"     * @throws DriverException\n     */\n    public function decodeImage(mixed $input, ?array $decoders = null): ImageInterface\n    {\n        $decoders = $decoders === null ? InputHandler::IMAGE_DECODERS : $decoders;\n\n        if (count($decoders) === 0) {\n            throw new InvalidArgumentException('No decoders in array');\n        }\n\n        try {\n            $result = InputHandler::usingDecoders($decoders, $this)->handle($input);\n        } catch (NotSupportedException) {\n            $type = is_object($input) ? $input::class : gettype($input);\n            throw new InvalidArgumentException('Unsupported image source type \"' . $type . '\"');\n        }\n\n        if (!$result instanceof ImageInterface) {\n            throw new ImageDecoderException('Result must be instance of ' . ImageInterface::class);\n        }\n\n        return $result;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see DriverInterface::decodeColor()\n     *\n     * @throws InvalidArgumentException\n     * @throws ColorDecoderException\n     * @throws DriverException\n     */\n    public function decodeColor(mixed $input, ?array $decoders = null): ColorInterface\n    {\n        $decoders = $decoders === null ? InputHandler::COLOR_DECODERS : $decoders;\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/Intervention/image/blob/5598b9e39751c34afc5cdee84abef77f92c26f68/src/Drivers/AbstractDriver.php#L52-L88","documentation":"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.","triggerScenarios":"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()]).","commonSituations":"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.","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"],"exampleFix":"// before\nclass S3Decoder implements DecoderInterface\n{\n    public function decode(mixed $input): mixed\n    {\n        return $this->s3->get($input); // raw bytes\n    }\n}\n\n// after\npublic function decode(mixed $input): ImageInterface\n{\n    return $this->driver->decodeImage($this->s3->get($input));\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isValidDecoder(mixed $decoder): bool\n{\n    return $decoder instanceof \\Intervention\\Image\\Interfaces\\DecoderInterface;\n}","tryCatchPattern":"try {\n    $image = $driver->decodeImage($input, [new MyDecoder()]);\n} catch (ImageDecoderException $e) {\n    // custom decoder broke the contract - fix its return type\n}","preventionTips":["Type custom decoders' return as ImageInterface so PHP enforces the contract","Delegate to built-in decoders inside custom ones"],"tags":["decoder","driver","contract","custom-extension"],"backgroundTag":"custom-decoder-invalid-return","analyzedSha":"5598b9e39751c34afc5cdee84abef77f92c26f68","analyzedAt":"2026-08-23T02:17:31.068Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}