composer/composer · error · UnexpectedValueException

{dir} does not exist and could not be created.

Error message

{dir} does not exist and could not be created.

What it means

Thrown by JsonFile::write() when the target directory does not exist AND @mkdir($dir, 0777, true) failed (the @ suppresses the warning; the false return triggers the exception). The recursive mkdir could not create the path — usually a permission denial or a parent that is not writable.

Source

Thrown at src/Composer/Json/JsonFile.php:154

     * @return void
     */
    public function write(array $hash, int $options = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
    {
        if ($this->path === 'php://memory') {
            file_put_contents($this->path, static::encode($hash, $options, $this->indent));

            return;
        }

        $dir = dirname($this->path);
        if (!is_dir($dir)) {
            if (file_exists($dir)) {
                throw new \UnexpectedValueException(
                    realpath($dir).' exists and is not a directory.'
                );
            }
            if (!@mkdir($dir, 0777, true)) {
                throw new \UnexpectedValueException(
                    $dir.' does not exist and could not be created.'
                );
            }
        }

        $retries = 3;
        while ($retries--) {
            try {
                $this->filePutContentsIfModified($this->path, static::encode($hash, $options, $this->indent). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
                break;
            } catch (\Exception $e) {
                if ($retries > 0) {
                    usleep(500000);
                    continue;
                }

                throw $e;
            }

View on GitHub (pinned to 6ffc117740)

Solutions

  1. Ensure the parent of the target directory exists and is writable by the PHP process.
  2. Fix ownership/permissions: `chown -R <user> <parent>` and `chmod -R u+w <parent>`.
  3. Check the filesystem is mounted read-write (`mount | grep <path>`).
  4. Remove any file occupying a parent path component that should be a directory.

Example fix

// before
$jsonFile->write($data);
// vendor/composer not creatable (read-only mount)

// after
chmod -R u+w vendor
# or fix the container mount to be read-write
$jsonFile->write($data);
Defensive patterns

Strategy: validation

Validate before calling

$dir = dirname($path);
if (!is_dir($dir)) {
    if (!@mkdir($dir, 0777, true)) {
        if (!is_writable(dirname($dir))) {
            throw new \UnexpectedValueException("Cannot create $dir: parent not writable");
        }
        throw new \UnexpectedValueException("Cannot create directory $dir");
    }
}

Type guard

function isDirCreatable(string $dir): bool {
    if (is_dir($dir)) return true;
    $parent = $dir;
    while (!is_dir($parent = dirname($parent))) {
        if (file_exists($parent)) return false;
    }
    return is_writable($parent);
}

Try / catch

try {
    $jsonFile->write($data);
} catch (\UnexpectedValueException $e) {
    if (str_contains($e->getMessage(), 'could not be created')) {
        // fix permissions/ownership/mount, then retry
    }
    throw $e;
}

Prevention

When it happens

Trigger: Calling write() where dirname($path) is missing and mkdir(..., true) returns false: no write permission on the parent, a read-only filesystem, or a parent path component is a file.

Common situations: vendor/ directory not writable (composer running as wrong user); read-only mount; a parent path component occupied by a file; running inside a container with a read-only bind mount; selinux denying directory creation.

Related errors


AI-assisted analysis of composer/composer@6ffc117740 (2026-08-07). Data as JSON: /api/errors/39be473437918104. Report an issue: GitHub.