Intervention/image · error · ModifierException
Failed to build watermark image
Error message
Failed to build watermark image
What it means
When insert() is called with transparency below 1.0, the GD driver builds a faded copy of the watermark on a new truecolor canvas of the same dimensions (imagecreatetruecolor). That call returns false when PHP cannot allocate the memory - roughly width x height x 4 bytes per canvas - and the modifier turns it into ModifierException 'Failed to build watermark image'. With the default transparency of 1.0 this code path is skipped entirely, so the error is specific to faded watermarks.
Source
Thrown at src/Drivers/Gd/Modifiers/InsertModifier.php:78
}
}
/**
* 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) {
throw new ModifierException('Failed to build watermark image');
}
imagealphablending($faded, false);
imagesavealpha($faded, true);
$watermarkNative = $watermark->core()->native();
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
$color = imagecolorat($watermarkNative, $x, $y);
$alpha = ($color >> 24) & 0x7F;
// GD stores alpha as 0 (opaque) … 127 (transparent), so scale
// the opacity (127 - alpha) and flip back to GD's convention.
$newAlpha = 127 - (int) round((127 - $alpha) * $this->transparency);
imagesetpixel($faded, $x, $y, ($newAlpha << 24) | ($color & 0xFFFFFF));
}
}
View on GitHub (pinned to 5598b9e397)
Solutions
- Pre-scale the watermark to its real display size before inserting it
- Raise the memory limit for the job: ini_set('memory_limit', '512M')
- Skip fading (transparency 1.0) - no extra canvas is allocated
- Catch ModifierException and fall back to inserting without transparency
Example fix
// before: fading a 6000x4000 watermark on a small memory limit $image->insert($watermarkPath, transparency: 0.5); // after: pre-scale the watermark, then fade it use Intervention\Image\ImageManager; use Intervention\Image\Drivers\Gd\Driver as GdDriver; $manager = new ImageManager(GdDriver::class); $watermark = $manager->decode(file_get_contents($watermarkPath))->scale(600); $image->insert($watermark, transparency: 0.5);
Defensive patterns
Strategy: fallback
Validate before calling
// rough memory check before fading a large watermark
$info = is_string($watermarkPath) ? getimagesize($watermarkPath) : false;
if ($info !== false) {
[$width, $height] = $info;
$requiredBytes = $width * $height * 4 * 2; // watermark + faded copy
$limitBytes = parse_size_shorthand(ini_get('memory_limit')); // e.g. '128M' -> bytes
if (memory_get_usage(true) + $requiredBytes > $limitBytes) {
// pre-scale to avoid the allocation failure
$watermark = $manager->decode(file_get_contents($watermarkPath))->scale(600);
$image->insert($watermark, transparency: 0.5);
return;
}
}
$image->insert($watermarkPath, transparency: 0.5); Try / catch
use Intervention\Image\Exceptions\ModifierException;
try {
$image->insert($watermark, transparency: 0.5);
} catch (ModifierException $e) {
// memory allocation failed: insert without the fade effect
$image->insert($watermark);
} Prevention
- Pre-scale watermarks to their real display size instead of fading full-resolution files.
- Budget roughly 4 bytes per pixel per canvas when estimating memory for GD operations.
- Raise memory_limit for batch jobs, not per-request code paths.
- Avoid transparency < 1.0 for very large watermarks.
When it happens
Trigger: $image->insert($hugeImage, transparency: 0.5) with dimensions large relative to memory_limit (e.g. 8000x6000 needs about 183 MB per canvas); low memory_limit on shared hosting or CLI workers; pipelines already holding a large base image plus the watermark.
Common situations: Full-resolution watermarks on print-sized images; default 128M memory_limit with large assets; batch jobs processing many images in one process without freeing memory.
Related errors
- Color channel value of {class} must be in range 0 to 1
- Failed to create new image while cloning
- Failed to build watermark
- Failed to apply {class}, unable to set transparency of water
- Failed to normalize background color to RGB color space
AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23).
Data as JSON: /api/errors/c1a07587da500ccf.
Report an issue: GitHub.