{"record":{"id":"38e91bd7775f27c4","repo":"getgrav/grav","slug":"the-class-s-does-not-implement-the-s-interfa","errorCode":null,"errorMessage":"The class '%s' does not implement the '%s' interface","messagePattern":"The class '(.+?)' does not implement the '(.+?)' interface","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Cache/Adapter/ChainCache.php","lineNumber":52,"sourceCode":"     * @param array $caches\n     * @param null|int|DateInterval $defaultLifetime\n     * @throws InvalidArgumentException\n     */\n    public function __construct(array $caches, $defaultLifetime = null)\n    {\n        try {\n            parent::__construct('', $defaultLifetime);\n        } catch (\\Psr\\SimpleCache\\InvalidArgumentException $e) {\n            throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);\n        }\n\n        if (!$caches) {\n            throw new InvalidArgumentException('At least one cache must be specified');\n        }\n\n        foreach ($caches as $cache) {\n            if (!$cache instanceof CacheInterface) {\n                throw new InvalidArgumentException(\n                    sprintf(\n                        \"The class '%s' does not implement the '%s' interface\",\n                        $cache::class,\n                        CacheInterface::class\n                    )\n                );\n            }\n        }\n\n        $this->caches = array_values($caches);\n        $this->count = count($caches);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function doGet($key, $miss)\n    {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Cache/Adapter/ChainCache.php#L34-L70","documentation":"Every member of a ChainCache must implement Grav\\Framework\\Cache\\CacheInterface (Grav's PSR-16-compatible contract). The constructor iterates the list and throws this InvalidArgumentException naming the offending class when a member does not. Mixing unrelated cache abstractions into the chain is the usual cause.","triggerScenarios":"Passing a PSR-6 CacheItemPoolInterface (Symfony/Doctrine cache pool), a Doctrine\\Common\\Cache instance, a Redis or Memcached client object, or a raw PSR-16 implementation from another vendor into `new ChainCache([...])` — none implement Grav's own CacheInterface.","commonSituations":"Porting code that used Doctrine Cache or Symfony Cache into a Grav extension; putting the Predis/Redis client where an adapter is expected; wrapping a third-party PSR-16 library assuming interface equality because the method names match.","solutions":["Use Grav's built-in adapters, all of which implement the interface: FileCache, RedisCache, MemcachedCache, SessionCache, MemoryCache, DoctrineCache.","Wrap foreign backends in an adapter class implementing Grav\\Framework\\Cache\\CacheInterface (you can reuse CacheTrait) and put that adapter in the chain.","For Doctrine specifically, use Grav's DoctrineCache adapter rather than passing the Doctrine instance raw."],"exampleFix":"// before\n$chain = new ChainCache([$redisClient, $psr6Pool]); // 'Redis' / 'Symfony\\\\Component\\\\Cache\\\\Adapter\\\\...' -> throws\n\n// after\nuse Grav\\Framework\\Cache\\Adapter\\RedisCache;\n$chain = new ChainCache([new RedisCache($redisClient)]);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"use Grav\\Framework\\Cache\\CacheInterface;\n\n/** @param CacheInterface[] $caches */\nfunction assertChainAdapters(array $caches): void\n{\n    foreach ($caches as $c) {\n        if (!$c instanceof CacheInterface) {\n            throw new \\InvalidArgumentException(get_class($c) . ' must be wrapped in a Grav cache adapter');\n        }\n    }\n}\n\nassertChainAdapters($caches);\n$chain = new ChainCache($caches);","tryCatchPattern":null,"preventionTips":["Only put Grav\\Framework\\Cache adapters (FileCache, RedisCache, MemcachedCache, ...) into a ChainCache.","Never pass raw clients (Redis, Predis, Memcached) or PSR-6 pools — wrap them first.","Let your IDE/phpstan enforce a `CacheInterface[]` docblock type on the constructor argument."],"tags":["grav","cache","chain-cache","interface-mismatch","psr-16"],"backgroundTag":"cache-adapter-misconfigured","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}