yiisoft/yii2 · error · yii\base\InvalidArgumentException
$ownership must be an integer, string, array, or null.
Error message
$ownership must be an integer, string, array, or null.
What it means
changeOwnership() accepts $ownership only as int (uid), string ('user' or 'user:group'), array (indexed [user, group] or associative ['user' => ..., 'group' => ...]), or null; every other type falls into the final else branch and throws InvalidArgumentException. This is a pure type-contract violation — the filesystem was never touched.
Source
Thrown at framework/helpers/BaseFileHelper.php:998
return;
}
$user = $group = null;
if (!empty($ownership) || $ownership === 0 || $ownership === '0') {
if (is_int($ownership)) {
$user = $ownership;
} elseif (is_string($ownership)) {
$ownerParts = explode(':', $ownership);
$user = $ownerParts[0];
if (count($ownerParts) > 1) {
$group = $ownerParts[1];
}
} elseif (is_array($ownership)) {
$ownershipIsIndexed = ArrayHelper::isIndexed($ownership);
$user = ArrayHelper::getValue($ownership, $ownershipIsIndexed ? 0 : 'user');
$group = ArrayHelper::getValue($ownership, $ownershipIsIndexed ? 1 : 'group');
} else {
throw new InvalidArgumentException('$ownership must be an integer, string, array, or null.');
}
}
if ($mode !== null) {
if (!is_int($mode)) {
throw new InvalidArgumentException('$mode must be an integer or null.');
}
if (!chmod($path, $mode)) {
throw new Exception('Unable to change mode of "' . $path . '" to "0' . decoct($mode) . '".');
}
}
if ($user !== null && $user !== '') {
if (is_numeric($user)) {
$user = (int) $user;
} elseif (!is_string($user)) {
throw new InvalidArgumentException('The user part of $ownership must be an integer, string, or null.');
}
if (!chown($path, $user)) {View on GitHub (pinned to 66f00d18a2)
Solutions
- Normalize to a supported scalar before calling: cast numeric uids to int or build a 'user:group' string yourself.
- Validate the value first: is_int || is_string || is_array || is_null.
- Fix the config source so ownership is a simple scalar like 'www-data:www-data'.
Example fix
// before
\yii\helpers\FileHelper::changeOwnership($file, $config->owner); // $config->owner is \stdClass
// after
$owner = is_array($config->owner)
? implode(':', [$config->owner['user'] ?? '', $config->owner['group'] ?? ''])
: (string) $config->owner;
\yii\helpers\FileHelper::changeOwnership($file, $owner); Defensive patterns
Strategy: type-guard
Validate before calling
$ok = $ownership === null || is_int($ownership) || is_string($ownership) || is_array($ownership);
if (!$ok) {
throw new \InvalidArgumentException('$ownership must be int, string, array, or null');
} Type guard
/** @param mixed $ownership */
function isOwnershipValue($ownership): bool
{
return $ownership === null
|| is_int($ownership)
|| is_string($ownership)
|| is_array($ownership);
} Prevention
- Keep ownership config as a scalar string ('www-data:www-data') rather than structured values.
- Validate values from JSON/YAML config before passing them to filesystem APIs.
- Watch for boolean defaults from config lookups (?? false) leaking into typed parameters.
When it happens
Trigger: changeOwnership($path, 1000.5) with a float uid; passing a stdClass/stdClass-like config object; a boolean sneaking in because a config lookup defaulted to false; a float produced by arithmetic on an uid before the call.
Common situations: Ownership values coming from JSON/YAML config (nested objects instead of scalars) forwarded unchecked; dynamic values where a null-coalescing default yields a bool; values extracted from an API payload with unknown shape.
Related errors
- The user part of $ownership must be an integer, string, or n
- The group part of $ownership must be an integer, string or n
- Exclude/include pattern must be a string.
- Unable to change ownership, "{$path}" is not a file or direc
- $mode must be an integer or null.
AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17).
Data as JSON: /api/errors/abf67272684c1695.
Report an issue: GitHub.