yiisoft/yii2 · error · yii\base\InvalidConfigException
Value must be convertable to string.
Error message
Value must be convertable to string.
What it means
When a relation is populated, ActiveRelationTrait::filterByModels() hashes the primary models' key values through normalizeModelKey(), which casts each value to string. Since 2.0.40 non-string values must be convertible; casting an array or an object without __toString() raises an engine error that the catch (\Exception) branch converts into InvalidConfigException with the message 'Value must be convertable to string.'
Source
Thrown at framework/db/ActiveRelationTrait.php:613
}
}
if (count($key) > 1) {
return serialize($key);
}
return reset($key);
}
/**
* @param mixed $value raw key value. Since 2.0.40 non-string values must be convertible to string (like special
* objects for cross-DBMS relations, for example: `|MongoId`).
* @return string normalized key value.
*/
private function normalizeModelKey($value)
{
try {
return (string)$value;
} catch (\Exception $e) {
throw new InvalidConfigException('Value must be convertable to string.');
} catch (\Throwable $e) {
throw new InvalidConfigException('Value must be convertable to string.');
}
}
/**
* @param array $primaryModels either array of AR instances or arrays
* @return array
*/
private function findJunctionRows($primaryModels)
{
if (empty($primaryModels)) {
return [];
}
$this->filterByModels($primaryModels);
/** @var ActiveRecord $primaryModel */
$primaryModel = reset($primaryModels);
if (!$primaryModel instanceof ActiveRecordInterface) {View on GitHub (pinned to 66f00d18a2)
Solutions
- Ensure the linked attribute holds a scalar (string/int) before accessing or eagerly loading the relation
- Implement __toString() on custom key-object classes used in link columns
- Fix the relation's link definition so it targets a real scalar column, not a container attribute
- For lists of ids stored in one attribute, query manually with where(['id' => $array]) instead of a relation
Example fix
// before
public function getOrders()
{
return $this->hasMany(Order::class, ['customer_id' => 'id']);
}
// $customer->id is an array (bad data) -> throws on $customer->orders
// after
$customer->id = (int) $raw; // normalize before relation access
$orders = $customer->orders; Defensive patterns
Strategy: validation
Validate before calling
foreach ($models as $model) {
$keyValue = $model->{$pkColumn};
if (!is_scalar($keyValue) && !(is_object($keyValue) && method_exists($keyValue, '__toString'))) {
throw new InvalidArgumentException('Relation key must be scalar or string-convertible.');
}
} Type guard
function isUsableRelationKey($value): bool
{
return is_scalar($value) || (is_object($value) && method_exists($value, '__toString'));
} Try / catch
try {
$orders = $customer->orders;
} catch (yii\base\InvalidConfigException $e) {
if (strpos($e->getMessage(), 'convertable to string') !== false) {
// key attribute holds a non-scalar: fail loudly with the offending value
throw new RuntimeException('Non-scalar relation key on customer.id', 0, $e);
}
throw $e;
} Prevention
- Validate relation key attributes at hydration time, not query time
- Implement __toString() on custom key objects
- Add tests exercising relations with real production-shaped key data
When it happens
Trigger: A relation's link points at an attribute that currently holds an array (e.g. a JSON column decoded to an array) or an object lacking __toString(); using relation methods with model instances whose key attributes were filled from unvalidated form input.
Common situations: JSON columns storing identifiers; upgrading from Yii < 2.0.40 where the cast silently produced garbage instead of an exception; custom key objects (cross-DBMS, e.g. MongoId-like classes) that never implemented __toString().
Related errors
- Primary key of '{$class}' can not be empty.
- "{}" must have a primary key.
- Relation names are case sensitive. {class} has a relation na
- Invalid link: it must be an array of key-value pairs.
- "{class}" must have a primary key.
AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17).
Data as JSON: /api/errors/c610370c2bbe736a.
Report an issue: GitHub.