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
- Verify the watermark exists and is a readable image before inserting: is_file(), is_readable(), getimagesize()
- Pass binary contents (file_get_contents(), Storage::disk()->get()) or an already-decoded ImageInterface instead of a fragile path
- Inspect $e->getPrevious() to find the real decoder error (FileNotFoundException, ImageDecoderException, ...)
- 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
- Validate watermark paths at boot (config check) rather than per request.
- Pass binary strings or decoded ImageInterface objects instead of paths in queue workers.
- Use absolute paths or resolve paths relative to a known root.
- Verify GD has the format support your watermark files need (gd_info()).
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
- Failed to build watermark image
- Color channel value of {class} must be in range 0 to 1
- Failed to apply {class}, unable to set transparency of water
- Failed to apply {class}, unable to insert watermark image
- Class '{objectShortname}' is not supported by {id} driver
AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23).
Data as JSON: /api/errors/886d8f2ef9c4f97a.
Report an issue: GitHub.