{"record":{"id":"bc2889ba350ec74c","repo":"yiisoft/yii2","slug":"unable-to-change-ownership-path-is-not-a-fil","errorCode":null,"errorMessage":"Unable to change ownership, \"{$path}\" is not a file or directory.","messagePattern":"Unable to change ownership, \"(.+?)\" is not a file or directory\\.","errorType":"exception","errorClass":"yii\\base\\InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"framework/helpers/BaseFileHelper.php","lineNumber":976,"sourceCode":"     * @param string $path the path to the file or directory.\n     * @param string|array|int|null $ownership the user and/or group ownership for the file or directory.\n     * When $ownership is a string, the format is 'user:group' where both are optional. E.g.\n     * 'user' or 'user:' will only change the user,\n     * ':group' will only change the group,\n     * 'user:group' will change both.\n     * When $owners is an index array the format is [0 => user, 1 => group], e.g. `[$myUser, $myGroup]`.\n     * It is also possible to pass an associative array, e.g. ['user' => $myUser, 'group' => $myGroup].\n     * In case $owners is an integer it will be used as user id.\n     * If `null`, an empty array or an empty string is passed, the ownership will not be changed.\n     * @param int|null $mode the permission to be set for the file or directory.\n     * If `null` is passed, the mode will not be changed.\n     *\n     * @since 2.0.43\n     */\n    public static function changeOwnership($path, $ownership, $mode = null)\n    {\n        if (!file_exists((string)$path)) {\n            throw new InvalidArgumentException('Unable to change ownership, \"' . $path . '\" is not a file or directory.');\n        }\n\n        if (empty($ownership) && $ownership !== 0 && $mode === null) {\n            return;\n        }\n\n        $user = $group = null;\n        if (!empty($ownership) || $ownership === 0 || $ownership === '0') {\n            if (is_int($ownership)) {\n                $user = $ownership;\n            } elseif (is_string($ownership)) {\n                $ownerParts = explode(':', $ownership);\n                $user = $ownerParts[0];\n                if (count($ownerParts) > 1) {\n                    $group = $ownerParts[1];\n                }\n            } elseif (is_array($ownership)) {\n                $ownershipIsIndexed = ArrayHelper::isIndexed($ownership);","sourceCodeStart":958,"sourceCodeEnd":994,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/helpers/BaseFileHelper.php#L958-L994","documentation":"FileHelper::changeOwnership() validates its target before touching anything: file_exists((string)$path) is the very first check, and a path that does not exist throws InvalidArgumentException. All later steps (chmod/chown/chgrp) assume a real filesystem node, so the guard prevents operating on typo'd paths, deleted files, or relative paths that resolved from the wrong working directory.","triggerScenarios":"changeOwnership('/srv/app/missing.txt', 'www-data') for a path with a typo or missing separator; a temp file already moved/deleted by another handler before the call; a relative path resolved against CLI cwd instead of the app root; a race with a cleanup job that removed the file.","commonSituations":"Post-upload permission fixups where the uploaded file was renamed/moved by a previous step; deployment scripts referencing files not yet created; paths built by naive concatenation ('/var/www' . 'app.css'); running the same code in different containers with different volume layouts.","solutions":["Check file_exists($path) (or is_file/is_dir for stricter intent) immediately before the call.","Build paths with Yii::getAlias() and rtrim($base, '/') . '/' . $name instead of bare concatenation.","Create or move the file first, then change ownership as a separate final step.","If the file is optional, skip the call rather than letting it throw."],"exampleFix":"// before\n\\yii\\helpers\\FileHelper::changeOwnership($tmpPath, 'www-data:www-data', 0644);\n\n// after\nif (is_file($tmpPath)) {\n    \\yii\\helpers\\FileHelper::changeOwnership($tmpPath, 'www-data:www-data', 0644);\n}","handlingStrategy":"validation","validationCode":"if (!file_exists($path)) {\n    throw new \\RuntimeException(\"Cannot change ownership — path does not exist: {$path}\");\n}\n\\yii\\helpers\\FileHelper::changeOwnership($path, 'www-data:www-data', 0644);","typeGuard":null,"tryCatchPattern":"try {\n    \\yii\\helpers\\FileHelper::changeOwnership($path, $ownership, $mode);\n} catch (\\yii\\base\\InvalidArgumentException $e) {\n    \\Yii::warning(\"changeOwnership rejected: {$e->getMessage()}\", 'files');\n}","preventionTips":["Build paths with Yii::getAlias() and explicit separators instead of concatenation.","Change ownership as the final step of a file-creation pipeline, after the file is guaranteed to exist.","Skip optional files explicitly rather than relying on the exception as control flow."],"tags":["filesystem","ownership","file-exists","yii2"],"backgroundTag":"file-not-found","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}