{"record":{"id":"13dea90e116ed75b","repo":"yiisoft/yii2","slug":"class-query-should-be-an-instance-of-yii-db","errorCode":null,"errorMessage":"\"{class}::$query\" should be an instance of \"yii\\db\\QueryInterface\".","messagePattern":"\"(.+?)::\\$query\" should be an instance of \"yii\\\\db\\\\QueryInterface\"\\.","errorType":"exception","errorClass":"InvalidConfigException","httpStatus":null,"severity":"error","filePath":"framework/caching/DbQueryDependency.php","lineNumber":79,"sourceCode":"\n\n    /**\n     * Generates the data needed to determine if dependency is changed.\n     *\n     * This method returns the query result.\n     * @param CacheInterface $cache the cache component that is currently evaluating this dependency\n     * @return mixed the data needed to determine if dependency has been changed.\n     * @throws InvalidConfigException on invalid configuration.\n     */\n    protected function generateDependencyData($cache)\n    {\n        $db = $this->db;\n        if ($db !== null) {\n            $db = Instance::ensure($db);\n        }\n\n        if (!$this->query instanceof QueryInterface) {\n            throw new InvalidConfigException('\"' . get_class($this) . '::$query\" should be an instance of \"yii\\db\\QueryInterface\".');\n        }\n\n        if (!empty($db->enableQueryCache)) {\n            // temporarily disable and re-enable query caching\n            $originEnableQueryCache = $db->enableQueryCache;\n            $db->enableQueryCache = false;\n            $result = $this->executeQuery($this->query, $db);\n            $db->enableQueryCache = $originEnableQueryCache;\n        } else {\n            $result = $this->executeQuery($this->query, $db);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Executes the query according to [[method]] specification.\n     * @param QueryInterface $query query to be executed.","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/caching/DbQueryDependency.php#L61-L97","documentation":"Thrown by yii\\caching\\DbQueryDependency::generateDependencyData() when the query property is not an instance of yii\\db\\QueryInterface — which includes the null case of never setting it. This dependency tracks changes by executing a Query object and hashing its results, so a raw SQL string, an array, a class name, or null cannot be used; ActiveQuery instances qualify because they implement QueryInterface.","triggerScenarios":"new DbQueryDependency(['query' => 'SELECT MAX(id) FROM post']) — a string instead of a Query; omitting query entirely; passing an array config like ['select' => ...] intended for a Query that was never instantiated; passing the AR class name or a query built for another component type (e.g. an Elasticsearch query object that does not implement the interface).","commonSituations":"Confusing DbDependency (sql string) with DbQueryDependency (Query object) and passing sql-style values; refactoring a dependency builder where the query construction was skipped; swapping the backing store while keeping the old dependency shape; IDE auto-completing 'sql' out of habit.","solutions":["Set query to a Query instance: 'query' => (new Query())->from('post')->orderBy('updated_at DESC')->limit(1) (values are hashed, keep them deterministic and small).","Remember ActiveQuery works too: 'query' => Post::find()->select(['updated_at'])->orderBy(['id' => SORT_DESC])->limit(1).","Never use raw SQL here — that is DbDependency's sql property.","Add an assertion right after constructing the dependency if it comes from dynamic config."],"exampleFix":"// before\n$dependency = new DbQueryDependency([\n    'query' => 'SELECT MAX(updated_at) FROM post', // string, not QueryInterface -> throws\n]);\n\n// after\n$dependency = new DbQueryDependency([\n    'query' => (new Query())\n        ->select(['MAX(updated_at)'])\n        ->from('post'),\n]);","handlingStrategy":"validation","validationCode":"if (!$dependency->query instanceof \\yii\\db\\QueryInterface) {\n    $dependency->query = (new \\yii\\db\\Query())->from('post')->select(['MAX(updated_at)']);\n}\nYii::$app->cache->set($key, $data, 0, $dependency);","typeGuard":"function isCacheableQuery($query): bool\n{\n    return $query instanceof \\yii\\db\\QueryInterface;\n}","tryCatchPattern":null,"preventionTips":["Remember the split: DbDependency takes a sql string, DbQueryDependency takes a Query object","Pass Query/ActiveQuery instances only — never raw SQL or arrays to the query property","Assert instanceof QueryInterface right after building dependencies from dynamic config"],"tags":["php","yii2","cache","dependency","query","configuration"],"backgroundTag":"missing-required-config","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}