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(): voidView on GitHub (pinned to f123cdb2a2)
Solutions
- Pre-create the directory in the pipeline or bootstrap: `mkdir -p build/logs` before running PHPUnit
- Grant write permission on the parent directory to the user running the tests (chown/chmod)
- Point the output file into a writable location such as the workspace or a mounted volume
- 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
- Pre-create output directories in CI (`mkdir -p build/logs`) as an explicit pipeline step
- Assert writability once in the bootstrap: is_writable(dirname($target)) for every configured report path
- Keep all report paths inside the workspace/build directory rather than system paths like /var/www
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
- Directory "%s" does not exist and could not be created
- Directory "%s" does not exist and could not be created
- Cannot write baseline to "%s".
- The path "%s" specified for the --log-events-text option cou
- "%s" does not match "socket://hostname:port" format
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/0d6750fc4186a010.
Report an issue: GitHub.