{"record":{"id":"866eff257a408b3f","repo":"yiisoft/yii2","slug":"unable-to-open-directory-dir","errorCode":null,"errorMessage":"Unable to open directory: $dir","messagePattern":"Unable to open directory: \\$dir","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"framework/helpers/BaseFileHelper.php","lineNumber":637,"sourceCode":"        if (!isset($options['basePath'])) {\n            // this should be done only once\n            $options['basePath'] = realpath($dir);\n            $options = static::normalizeOptions($options);\n        }\n\n        return $options;\n    }\n\n    /**\n     * @param string $dir\n     * @return resource\n     * @throws InvalidArgumentException if unable to open directory\n     */\n    private static function openDir($dir)\n    {\n        $handle = opendir($dir);\n        if ($handle === false) {\n            throw new InvalidArgumentException(\"Unable to open directory: $dir\");\n        }\n        return $handle;\n    }\n\n    /**\n     * @param string $dir\n     * @return string\n     * @throws InvalidArgumentException if directory not exists\n     */\n    private static function clearDir($dir)\n    {\n        if (!is_dir($dir)) {\n            throw new InvalidArgumentException(\"The dir argument must be a directory: $dir\");\n        }\n        return rtrim($dir, '\\/');\n    }\n\n    /**","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/helpers/BaseFileHelper.php#L619-L655","documentation":"Thrown by the private openDir() helper in yii\\helpers\\BaseFileHelper when PHP's opendir() returns false for the given path. Every FileHelper scan operation (findFiles(), findDirectories(), copyDirectory(), removeDirectory()) funnels through it, so a missing or unreadable directory aborts the whole scan with an InvalidArgumentException that names the offending path. It exists to fail fast instead of silently returning an empty result set for a broken path.","triggerScenarios":"Calling FileHelper::findFiles($dir) / findDirectories() / copyDirectory() where $dir does not exist, is a regular file, or is not readable by the PHP process; running under PHP-FPM/Apache with an open_basedir directive that excludes $dir; passing a relative path that resolves against an unexpected current working directory (CLI vs web).","commonSituations":"Deployment scripts scanning runtime folders (runtime/cache, uploads/) that were cleared or never created on the new host; shared hosting with open_basedir limits; permission differences between CLI (root) and web server user; a race where another process deletes the directory between the caller's is_dir() check and the scan.","solutions":["Verify and repair the path before scanning: if (!is_dir($dir)) mkdir($dir, 0775, true); and confirm is_readable($dir).","Always pass absolute paths resolved through Yii::getAlias(), e.g. FileHelper::findFiles(Yii::getAlias('@runtime/exports')).","On shared hosting, inspect open_basedir in phpinfo() and move the scanned directory inside the allowed paths (or ask the host to widen the directive).","For optional directories, wrap the scan in try/catch (InvalidArgumentException) and treat failure as an empty result."],"exampleFix":"// before\n$files = \\yii\\helpers\\FileHelper::findFiles(\\Yii::getAlias('@app/attachments'));\n\n// after\n$dir = \\Yii::getAlias('@app/attachments');\nif (!is_dir($dir)) {\n    mkdir($dir, 0775, true);\n}\n$files = is_readable($dir) ? \\yii\\helpers\\FileHelper::findFiles($dir) : [];","handlingStrategy":"validation","validationCode":"$dir = \\Yii::getAlias('@webroot/uploads');\nif (!is_dir($dir)) {\n    throw new \\RuntimeException(\"Directory missing: {$dir}\");\n}\nif (!is_readable($dir)) {\n    throw new \\RuntimeException(\"Directory not readable by PHP user: {$dir}\");\n}\n$files = \\yii\\helpers\\FileHelper::findFiles($dir);","typeGuard":null,"tryCatchPattern":"try {\n    $files = \\yii\\helpers\\FileHelper::findFiles($dir);\n} catch (\\yii\\base\\InvalidArgumentException $e) {\n    \\Yii::warning(\"Scan skipped: {$e->getMessage()}\", 'filehelper');\n    $files = [];\n}","preventionTips":["Create scan-target directories during deployment (mkdir -p) instead of assuming they exist.","Resolve every filesystem path through Yii::getAlias() so paths are absolute and rooted in known aliases.","Grant the web server user read+execute on every directory being scanned.","When moving to shared hosting, check open_basedir covers all scanned paths."],"tags":["filesystem","directory","permissions","opendir","yii2"],"backgroundTag":"directory-access-denied","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}