Intervention/image · error · ModifierException

Failed to build watermark

Error message

Failed to build watermark

What it means

Before compositing, InsertModifier::watermark() decodes the watermark source through the driver pipeline (driver()->decodeImage($this->image)). Any ImageException raised there - missing or unreadable file, corrupt or truncated data, unsupported source type, missing GD format support - is wrapped into ModifierException 'Failed to build watermark' with the original cause available via getPrevious(). This is the most commonly hit insert() failure.

Source

Thrown at src/Drivers/Gd/Modifiers/InsertModifier.php:59

            );
        }

        return $image;
    }

    /**
     * Build watermark image.
     *
     * @throws ModifierException
     */
    private function watermark(): ImageInterface
    {
        try {
            $watermark = $this->driver()->decodeImage($this->image);

            return $this->transparency === 1.0 ? $watermark : $this->fadeWatermark($watermark);
        } catch (ImageException $e) {
            throw new ModifierException('Failed to build watermark', previous: $e);
        }
    }

    /**
     * Build a faded copy of the watermark by scaling each pixel's alpha
     * by the requested transparency factor of the modifier. Created once
     * and reused for every frame.
     *
     * @throws ModifierException
     */
    private function fadeWatermark(ImageInterface $watermark): ImageInterface
    {
        $width = $watermark->width();
        $height = $watermark->height();

        $faded = imagecreatetruecolor($width, $height);

        if ($faded === false) {

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Verify the watermark exists and is a readable image before inserting: is_file(), is_readable(), getimagesize()
  2. Pass binary contents (file_get_contents(), Storage::disk()->get()) or an already-decoded ImageInterface instead of a fragile path
  3. Inspect $e->getPrevious() to find the real decoder error (FileNotFoundException, ImageDecoderException, ...)
  4. Enable the required GD format (webp/avif) or convert the watermark to PNG/JPEG

Example fix

// before
$image->insert(config('services.watermark.path'));

// after
$path = (string) config('services.watermark.path');
if (!is_file($path) || !is_readable($path)) {
    throw new RuntimeException('Watermark file missing or unreadable: ' . $path);
}
$image->insert(file_get_contents($path));
Defensive patterns

Strategy: validation

Validate before calling

$path = 'watermarks/logo.png';

if (is_string($path)) {
    if (!is_file($path) || !is_readable($path)) {
        throw new RuntimeException('Watermark file missing or unreadable: ' . $path);
    }
    if (getimagesize($path) === false) {
        throw new RuntimeException('Watermark is not a valid image: ' . $path);
    }
}

$image->insert(is_string($path) ? file_get_contents($path) : $path);

Try / catch

use Intervention\Image\Exceptions\ModifierException;

try {
    $image->insert($watermark);
} catch (ModifierException $e) {
    $reason = $e->getPrevious()?->getMessage() ?? $e->getMessage();
    $logger->error('Watermark insert failed: ' . $reason);
    // proceed without watermark
}

Prevention

When it happens

Trigger: $image->insert('watermark.png') with a wrong path or a path relative to a different working directory; passing an empty string, null or garbage binary; using a truncated/corrupt uploaded logo; WebP/AVIF watermarks without corresponding GD support; remote URLs when allow_url_fopen is off; passing a Laravel Storage::path() for a non-local disk.

Common situations: Watermark paths from env/config files that differ between environments; queue workers with a different cwd than web requests; user-supplied logos; shared hosts with partial GD format support.

Related errors


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