{"record":{"id":"68fa6cd7af67beb5","repo":"yiisoft/yii2","slug":"the-dir-argument-must-be-a-directory-dir","errorCode":null,"errorMessage":"The dir argument must be a directory: $dir","messagePattern":"The dir argument must be a directory: \\$dir","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"framework/helpers/BaseFileHelper.php","lineNumber":650,"sourceCode":"     */\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    /**\n     * Checks if the given file path satisfies the filtering options.\n     * @param string $path the path of the file or directory to be checked\n     * @param array $options the filtering options. See [[findFiles()]] for explanations of\n     * the supported options.\n     * @return bool whether the file or directory satisfies the filtering options.\n     */\n    public static function filterPath($path, $options)\n    {\n        if (isset($options['filter'])) {\n            $result = call_user_func($options['filter'], $path);\n            if (is_bool($result)) {\n                return $result;\n            }","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/helpers/BaseFileHelper.php#L632-L668","documentation":"clearDir() is an internal guard in BaseFileHelper used by directory mutation helpers (removeDirectory() and friends) that throws InvalidArgumentException when is_dir($dir) is false. Its job is to stop destructive operations before they start when the target is a regular file, a dangling symlink, or a path already deleted by someone else. The message names the path so the caller can see exactly what failed the check.","triggerScenarios":"FileHelper::removeDirectory($path) or copyDirectory() where $path is actually a regular file; a symlink whose target was deleted (is_dir() on a dead symlink returns false); the directory being removed by a concurrent process between the caller's check and the call; a path variable accidentally holding an uploaded file's path instead of its parent directory.","commonSituations":"Cleanup cron jobs racing with concurrent deletes; file-upload handlers mixing file paths and directory paths in the same variable; dangling symlinks in shared temp directories; test fixtures creating a file where the code expects a directory.","solutions":["Guard the call: if (is_dir($path)) { FileHelper::removeDirectory($path); } so cleanup is idempotent.","Resolve the path first with realpath($path) to collapse symlinks and verify what is really on disk.","Fix the upstream path bug — make sure the variable holds the directory (dirname()) rather than a file inside it.","If the directory must exist afterwards, recreate it with mkdir($path, 0775, true) after removal."],"exampleFix":"// before\n\\yii\\helpers\\FileHelper::removeDirectory(\\Yii::getAlias('@runtime/cache/segments'));\n\n// after\n$dir = \\Yii::getAlias('@runtime/cache/segments');\nif (is_dir($dir)) {\n    \\yii\\helpers\\FileHelper::removeDirectory($dir);\n}","handlingStrategy":"validation","validationCode":"if (!is_dir($dir)) {\n    return; // nothing to clean — missing path or a regular file\n}\n\\yii\\helpers\\FileHelper::removeDirectory($dir);","typeGuard":"/** Narrow a path to an existing directory, or null. */\nfunction toExistingDir(string $path): ?string\n{\n    $real = realpath($path);\n    return ($real !== false && is_dir($real)) ? $real : null;\n}","tryCatchPattern":"try {\n    \\yii\\helpers\\FileHelper::removeDirectory($dir);\n} catch (\\yii\\base\\InvalidArgumentException $e) {\n    \\Yii::warning(\"Cleanup skipped: {$e->getMessage()}\", 'filehelper');\n}","preventionTips":["Treat directory cleanup as idempotent — never assume the directory survived since the last check.","Resolve user-supplied paths with realpath() before destructive calls.","Keep file paths and their parent directory paths in separate, clearly named variables."],"tags":["filesystem","directory","validation","remove-directory","yii2"],"backgroundTag":"path-not-a-directory","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}