yiisoft/yii2 · error · InvalidConfigException
"{class}::$query" should be an instance of "yii\db\QueryInte
Error message
"{class}::$query" should be an instance of "yii\db\QueryInterface". What it means
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.
Source
Thrown at framework/caching/DbQueryDependency.php:79
/**
* Generates the data needed to determine if dependency is changed.
*
* This method returns the query result.
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
* @return mixed the data needed to determine if dependency has been changed.
* @throws InvalidConfigException on invalid configuration.
*/
protected function generateDependencyData($cache)
{
$db = $this->db;
if ($db !== null) {
$db = Instance::ensure($db);
}
if (!$this->query instanceof QueryInterface) {
throw new InvalidConfigException('"' . get_class($this) . '::$query" should be an instance of "yii\db\QueryInterface".');
}
if (!empty($db->enableQueryCache)) {
// temporarily disable and re-enable query caching
$originEnableQueryCache = $db->enableQueryCache;
$db->enableQueryCache = false;
$result = $this->executeQuery($this->query, $db);
$db->enableQueryCache = $originEnableQueryCache;
} else {
$result = $this->executeQuery($this->query, $db);
}
return $result;
}
/**
* Executes the query according to [[method]] specification.
* @param QueryInterface $query query to be executed.View on GitHub (pinned to 66f00d18a2)
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.
Example fix
// before
$dependency = new DbQueryDependency([
'query' => 'SELECT MAX(updated_at) FROM post', // string, not QueryInterface -> throws
]);
// after
$dependency = new DbQueryDependency([
'query' => (new Query())
->select(['MAX(updated_at)'])
->from('post'),
]); Defensive patterns
Strategy: validation
Validate before calling
if (!$dependency->query instanceof \yii\db\QueryInterface) {
$dependency->query = (new \yii\db\Query())->from('post')->select(['MAX(updated_at)']);
}
Yii::$app->cache->set($key, $data, 0, $dependency); Type guard
function isCacheableQuery($query): bool
{
return $query instanceof \yii\db\QueryInterface;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- DbDependency::sql must be set.
- FileDependency::fileName must be set
- The 'host' property must be specified for every memcache ser
- You should configure "cache" component to use database befor
- Cost must be between 4 and 31.
AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17).
Data as JSON: /api/errors/13dea90e116ed75b.
Report an issue: GitHub.