yiisoft/yii2 · error · InvalidArgumentException

The dir argument must be a directory: $dir

Error message

The dir argument must be a directory: $dir

What it means

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.

Source

Thrown at framework/helpers/BaseFileHelper.php:650

     */
    private static function openDir($dir)
    {
        $handle = opendir($dir);
        if ($handle === false) {
            throw new InvalidArgumentException("Unable to open directory: $dir");
        }
        return $handle;
    }

    /**
     * @param string $dir
     * @return string
     * @throws InvalidArgumentException if directory not exists
     */
    private static function clearDir($dir)
    {
        if (!is_dir($dir)) {
            throw new InvalidArgumentException("The dir argument must be a directory: $dir");
        }
        return rtrim($dir, '\/');
    }

    /**
     * Checks if the given file path satisfies the filtering options.
     * @param string $path the path of the file or directory to be checked
     * @param array $options the filtering options. See [[findFiles()]] for explanations of
     * the supported options.
     * @return bool whether the file or directory satisfies the filtering options.
     */
    public static function filterPath($path, $options)
    {
        if (isset($options['filter'])) {
            $result = call_user_func($options['filter'], $path);
            if (is_bool($result)) {
                return $result;
            }

View on GitHub (pinned to 66f00d18a2)

Solutions

  1. Guard the call: if (is_dir($path)) { FileHelper::removeDirectory($path); } so cleanup is idempotent.
  2. Resolve the path first with realpath($path) to collapse symlinks and verify what is really on disk.
  3. Fix the upstream path bug — make sure the variable holds the directory (dirname()) rather than a file inside it.
  4. If the directory must exist afterwards, recreate it with mkdir($path, 0775, true) after removal.

Example fix

// before
\yii\helpers\FileHelper::removeDirectory(\Yii::getAlias('@runtime/cache/segments'));

// after
$dir = \Yii::getAlias('@runtime/cache/segments');
if (is_dir($dir)) {
    \yii\helpers\FileHelper::removeDirectory($dir);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!is_dir($dir)) {
    return; // nothing to clean — missing path or a regular file
}
\yii\helpers\FileHelper::removeDirectory($dir);

Type guard

/** Narrow a path to an existing directory, or null. */
function toExistingDir(string $path): ?string
{
    $real = realpath($path);
    return ($real !== false && is_dir($real)) ? $real : null;
}

Try / catch

try {
    \yii\helpers\FileHelper::removeDirectory($dir);
} catch (\yii\base\InvalidArgumentException $e) {
    \Yii::warning("Cleanup skipped: {$e->getMessage()}", 'filehelper');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17). Data as JSON: /api/errors/68fa6cd7af67beb5. Report an issue: GitHub.