sebastianbergmann/phpunit · error · 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

DefaultTestRunHistory::writeToFile() (reached from persist()/persistAndPrune()) stores the test run history file and, like the test index, first tries Filesystem::createDirectory() on dirname($this->filename); when creation fails it throws DirectoryDoesNotExistException('Directory "%s" does not exist and could not be created'). The parent directory of the run-history file neither exists nor is creatable by the PHP process.

Source

Thrown at src/Runner/TestRunHistory/DefaultTestRunHistory.php:182

    /**
     * Persists only the entries that were touched since load(). This drops
     * the entries of tests that no longer exist and must only be used when
     * the current test run executed every test that exists.
     *
     * @throws Exception
     */
    public function persistAndPrune(): void
    {
        $this->writeToFile(true);
    }

    /**
     * @throws Exception
     */
    private function writeToFile(bool $prune): void
    {
        if (!Filesystem::createDirectory(dirname($this->filename))) {
            throw new DirectoryDoesNotExistException(dirname($this->filename));
        }

        $handle = fopen($this->filename, 'c+');

        if ($handle === false) {
            // @codeCoverageIgnoreStart
            return;
            // @codeCoverageIgnoreEnd
        }

        flock($handle, LOCK_EX);

        if ($prune) {
            $defects = [];

            foreach ($this->defects as $id => $status) {
                if (isset($this->changedDefects[$id])) {
                    $defects[$id] = $status;

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Create the directory beforehand and make it writable by the PHP process: mkdir -p path/to/dir.
  2. Configure the run history/cache location to a writable directory.
  3. Verify open_basedir settings and that the volume is mounted read-write in containers.

Example fix

# before
phpunit   # writeToFile() fails: Directory "/var/cache/phpunit" does not exist and could not be created

# after
mkdir -p /var/cache/phpunit
phpunit
Defensive patterns

Strategy: validation

Validate before calling

// before persisting the run history, ensure its directory is writable
$dir = dirname($historyFilename);
if (!is_dir($dir) && !@mkdir($dir, 0777, true) && !is_dir($dir)) {
    throw new RuntimeException("Cannot create run-history directory {$dir}");
}
if (!is_writable($dir)) {
    throw new RuntimeException("Run-history directory {$dir} is not writable");
}

Prevention

When it happens

Trigger: Persisting the run history when its target directory is missing and cannot be created — read-only filesystem, missing write permission, or a path excluded by open_basedir.

Common situations: CI containers with read-only project mounts; a run-history path pointing outside the sandbox; permission changes between runs (running as different users).

Related errors


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