sebastianbergmann/phpunit · error · PHPUnit\Runner\DirectoryDoesNotExistException

Directory "%s" does not exist and could not be created

Error message

Directory "%s" does not exist and could not be created

What it means

For regular (non-socket, non-php://) output targets, DefaultPrinter tries to create the parent directory of the output file via Filesystem::createDirectory(dirname($out)). If the directory does not exist and cannot be created, it throws DirectoryDoesNotExistException. This guards against silently losing output when fopen() would fail later.

Source

Thrown at src/TextUI/Output/Printer/DefaultPrinter.php:100

            if (count($tmp) !== 2) {
                throw new InvalidSocketException($out);
            }

            $stream = @fsockopen($tmp[0], (int) $tmp[1]);

            if ($stream === false) {
                throw new CannotOpenSocketException($tmp[0], (int) $tmp[1]);
            }

            $this->stream = $stream;
            $this->isOpen = true;

            return;
        }

        if (!$this->isPhpStream && !Filesystem::createDirectory(dirname($out))) {
            throw new DirectoryDoesNotExistException(dirname($out));
        }

        $stream = fopen($out, 'wb');

        assert($stream !== false);

        $this->stream = $stream;
        $this->isOpen = true;
    }

    public function print(string $buffer): void
    {
        assert($this->isOpen);

        fwrite($this->stream, $buffer);
    }

    public function flush(): void

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Pre-create the directory in the pipeline or bootstrap: `mkdir -p build/logs` before running PHPUnit
  2. Grant write permission on the parent directory to the user running the tests (chown/chmod)
  3. Point the output file into a writable location such as the workspace or a mounted volume
  4. Use an absolute path you have verified is writable instead of a path inherited from a different working directory

Example fix

# before
$ vendor/bin/phpunit --log-junit /var/www/app/build/results.xml
# DirectoryDoesNotExistException: "/var/www/app/build" does not exist and could not be created

# after
$ mkdir -p /var/www/app/build && chmod u+w /var/www/app/build
$ vendor/bin/phpunit --log-junit /var/www/app/build/results.xml
Defensive patterns

Strategy: validation

Validate before calling

$target = 'build/logs/results.xml';
$dir = dirname($target);
if (!is_dir($dir) && !mkdir($dir, 0777, true) && !is_dir($dir)) {
    throw new RuntimeException("Cannot create output directory {$dir}");
}
if (!is_writable($dir)) {
    throw new RuntimeException("Output directory {$dir} is not writable");
}

Try / catch

use PHPUnit\TextUI\Output\Printer\DirectoryDoesNotExistException;

try {
    $printer = DefaultPrinter::from($target);
} catch (DirectoryDoesNotExistException $e) {
    // create the directory in a temporary location or fall back to stdout
    $printer = DefaultPrinter::standardOutput();
    error_log($e->getMessage());
}

Prevention

When it happens

Trigger: Constructing DefaultPrinter with a file target such as 'build/logs/results.txt' (or configuring report output paths) where the parent directory does not exist and mkdir() fails due to missing write permissions, a read-only filesystem, or open_basedir restrictions.

Common situations: CI images running as non-root trying to write under /var/www or other root-owned paths; read-only volume mounts in containers; output/cache paths that broke after the project was moved or the pipeline changed user.

Related errors


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/0d6750fc4186a010. Report an issue: GitHub.