Intervention/image · error · FileNotWritableException

Failed to write file to path " . $path

Error message

Failed to write file to path " . $path

What it means

File::save() finally writes with file_put_contents($path, $this->toStream()) and throws FileNotWritableException when that call returns false. All pre-checks (directory exists, directory writable, existing file writable) passed, so the failure happened during the write itself: the disk or inode pool is full, a quota was hit, or the filesystem errored (NFS/remote mount issues, fs corruption).

Source

Thrown at src/File.php:108

        }

        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,
            );
        }
    }

    /**
     * {@inheritdoc}
     *
     * @see FileInterface::toString()
     *
     * @throws StreamException
     */
    public function toString(): string
    {
        $data = stream_get_contents($this->toStream(), offset: 0);

        if ($data === false) {
            throw new StreamException('Unable to read data from stream');

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Check free space and inodes: df -h and df -i; free space or expand the volume
  2. Catch FileNotWritableException around save(), surface an actionable error (storage full) instead of a generic failure, and alert ops
  3. Add disk-space monitoring and a best-effort guard with disk_free_space() before heavy write batches

Example fix

// before
$image->save($path); // throws 'Failed to write file to path ...' when disk is full

// after
try {
    $image->save($path);
} catch (FileNotWritableException $e) {
    Logger::error('image save failed', ['path' => $path, 'free' => disk_free_space(dirname($path))]);
    throw new RuntimeException('Image could not be stored; disk full or quota exceeded', 0, $e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

$dir = pathinfo($path, PATHINFO_DIRNAME);
if (disk_free_space($dir) === false || disk_free_space($dir) < $expectedBytes) {
    throw new RuntimeException('Insufficient disk space for image write');
}
// best-effort only: the disk can still fill between check and write

Try / catch

use Intervention\Image\Exceptions\FileNotWritableException;

try {
    $image->save($path);
} catch (FileNotWritableException $e) {
    // pre-checks passed, so the write itself failed: disk full, quota, fs error
    report('Image write failed: ' . $path . ' free=' . disk_free_space(dirname($path)));
    throw $e;
}

Prevention

When it happens

Trigger: Writing a large encoded image to a full disk (df shows 100%); hitting an inode limit; exceeding a user/group quota on shared hosting; writing to a failing NFS mount where metadata checks still succeed.

Common situations: Upload/storage volumes filling up in production; log or image caches growing unbounded; shared hosting quotas; long-running jobs whose disk filled after the pre-checks passed.

Related errors


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