yiisoft/yii2 · error · yii\base\InvalidConfigException
The ArrayExpression class can not be iterated when the value
Error message
The ArrayExpression class can not be iterated when the value is a QueryInterface object
What it means
ArrayExpression wraps either a concrete PHP array or a subquery (QueryInterface) for use as an SQL array literal. Its getIterator() (invoked by foreach) can only walk a real array; when the wrapped value is a QueryInterface instance there is nothing to iterate client-side, so InvalidConfigException is thrown instead of silently iterating the query object.
Source
Thrown at framework/db/ArrayExpression.php:199
{
return count($this->value);
}
/**
* Retrieve an external iterator
*
* @link https://www.php.net/manual/en/iteratoraggregate.getiterator.php
* @return Traversable An instance of an object implementing <b>Iterator</b> or
* <b>Traversable</b>
* @since 2.0.14.1
* @throws InvalidConfigException when ArrayExpression contains QueryInterface object
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$value = $this->getValue();
if ($value instanceof QueryInterface) {
throw new InvalidConfigException('The ArrayExpression class can not be iterated when the value is a QueryInterface object');
}
if ($value === null) {
$value = [];
}
return new \ArrayIterator($value);
}
}
View on GitHub (pinned to 66f00d18a2)
Solutions
- Keep the original PHP array for iteration and use ArrayExpression only when composing SQL
- Guard before iterating: $v = $expr->getValue(); if (!$v instanceof QueryInterface) { foreach ($v as ...) }
- If you actually need the subquery's rows, run it (->column()/->all()) and iterate the result
- Type-hint shared helpers to accept only arrays, not Traversable, when expression inputs are possible
Example fix
// before
$expr = new ArrayExpression((new Query())->select('id')->from('tag'));
foreach ($expr as $tagId) { ... } // throws
// after
$tagIds = (new Query())->select('id')->from('tag')->column();
foreach ($tagIds as $tagId) { ... }
// use new ArrayExpression($tagIds) only when embedding in SQL Defensive patterns
Strategy: type-guard
Type guard
function isIterableArrayExpression(\yii\db\ArrayExpression $expr): bool
{
$value = $expr->getValue();
return $value === null || !$value instanceof \yii\db\QueryInterface;
} Try / catch
try {
foreach ($expr as $item) { /* ... */ }
} catch (yii\base\InvalidConfigException $e) {
if (strpos($e->getMessage(), 'ArrayExpression') !== false) {
$items = (new Query())->... ->column(); // materialize the subquery instead
} else {
throw $e;
}
} Prevention
- Keep raw arrays for iteration; wrap in ArrayExpression only at SQL composition time
- Type-hint helpers that iterate as array, not iterable
- Never foreach over values that may be expression objects
When it happens
Trigger: foreach ($arrayExpression as $v) after constructing it with (new Query())->select('id')->from('t') as the value; passing the expression into generic helpers that iterate their input (ArrayHelper, implode, json_encode of traversables); debugging by looping over an expression built for SQL.
Common situations: Code that accepts array|Expression union types and hits the subquery variant; developers inspecting expression objects during query debugging; reusing a value that is sometimes an array and sometimes a subquery.
Related errors
- "{class}::$query" should be an instance of "yii\db\QueryInte
- Unknown scenario: $scenario
- Invalid validation rule: a rule must specify both attribute
- The directory does not exist: $path
- Controller class must extend from \yii\base\Controller.
AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17).
Data as JSON: /api/errors/a30d39156939855d.
Report an issue: GitHub.