Intervention/image · error · FileNotWritableException

Can't write to path. Directory "' . $dir . '" is not writabl

Error message

Can't write to path. Directory "' . $dir . '" is not writable

What it means

After confirming the directory exists, File::save() checks is_writable($dir) and throws FileNotWritableException when the PHP process lacks write permission on that directory. This is a classic ownership mismatch: the directory belongs to a different user than the one PHP runs as (www-data, php-fpm user, queue worker user).

Source

Thrown at src/File.php:93

            throw new InvalidArgumentException('Path must not be an empty string');
        }

        if (strlen($path) > PHP_MAXPATHLEN) {
            throw new InvalidArgumentException(
                "Path is longer than the configured max. value of " . PHP_MAXPATHLEN,
            );
        }

        $dir = pathinfo($path, PATHINFO_DIRNAME);

        if (!is_dir($dir)) {
            throw new DirectoryNotFoundException(
                'Can\'t write to path. Directory "' . $dir . '" does not exist',
            );
        }

        if (!is_writable($dir)) {
            throw new FileNotWritableException(
                'Can\'t write to path. Directory "' . $dir . '" is not writable',
            );
        }

        if (is_file($path) && !is_writable($path)) {
            throw new FileNotWritableException(
                "Can't write to path. Existing file " . $path . " is not writable",
            );
        }

        // write data
        $saved = file_put_contents($path, $this->toStream());

        if ($saved === false) {
            throw new FileNotWritableException(
                "Failed to write file to path " . $path,
            );
        }

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Give the PHP user write access: chown the directory to the web server user or a shared group, and use chmod 775
  2. Use ACLs for multi-user setups: setfacl -m u:www-data:rwx storage/uploads
  3. Verify the mount is writable and not read-only (check docker-compose volumes, /etc/fstab, SELinux context)

Example fix

# before: dir owned by deploy user, mode 755 -> www-data cannot write
# after:
sudo chgrp www-data storage/uploads
sudo chmod 775 storage/uploads
# or per-user ACL without changing group:
sudo setfacl -m u:www-data:rwx storage/uploads
Defensive patterns

Strategy: validation

Validate before calling

$dir = pathinfo($path, PATHINFO_DIRNAME);
if (!is_writable($dir)) {
    throw new RuntimeException('Storage directory not writable by PHP user: ' . $dir);
}
$encoded->save($path);

Try / catch

use Intervention\Image\Exceptions\FilesystemException;

try {
    $image->save($path);
} catch (FilesystemException $e) {
    // check ownership/modes before retrying; do not blind-retry
    throw new RuntimeException('Cannot save image: ' . $e->getMessage(), 0, $e);
}

Prevention

When it happens

Trigger: Saving to a directory owned by the deploy user with mode 755 while PHP-FPM runs as www-data; writing into a read-only container mount; SELinux or AppArmor denying writes despite permissive Unix modes; shared hosting where the storage dir belongs to another FTP account.

Common situations: Files uploaded/deployed as root and never chowned; Laravel-style storage dirs created by CLI then written by the web user; NFS mounts with root_squash; containers with read-only volumes.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23). Data as JSON: /api/errors/87a780ca2c4357db. Report an issue: GitHub.