Intervention/image · error · Intervention\Image\Exceptions\DriverException

Failed to add image frame

Error message

Failed to add image frame

What it means

Thrown by Core::add() when appending a FrameInterface to the Imagick core fails. add() copies delay, disposal method and page geometry onto the frame's native Imagick object and then calls Imagick::addImage(); any ImagickException during those steps is rethrown as this DriverException.

Source

Thrown at src/Drivers/Imagick/Core.php:209

        try {
            $imagick->setImageDelay(
                (int) round($frame->delay() * 100),
            );

            $imagick->setImageDispose($frame->disposalMethod());

            $size = $frame->size();
            $imagick->setImagePage(
                $size->width(),
                $size->height(),
                $frame->offsetLeft(),
                $frame->offsetTop(),
            );

            $this->imagick->addImage($imagick);
        } catch (ImagickException $e) {
            throw new DriverException('Failed to add image frame', previous: $e);
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     *
     * @see CoreInterface::count()
     *
     * @throws DriverException
     */
    public function count(): int
    {
        try {
            return $this->imagick->getNumberImages();
        } catch (ImagickException $e) {
            throw new DriverException('Failed to count image frames', previous: $e);

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Inspect $e->getPrevious() for the underlying ImagickException message
  2. Create a fresh frame (or clone its native Imagick) for each add() call instead of reusing one instance
  3. Ensure every frame comes from the same Imagick driver pipeline ($frame->native() instanceof Imagick)
  4. Validate delay: $frame->setDelay(max(0, $delay)) before adding
  5. Wrap animation assembly in try/catch on DriverException and abort the batch on failure

Example fix

// before: adding the same frame object repeatedly
foreach ($sources as $src) {
    $image->core()->add($frame);
}

// after: fresh frame per iteration
foreach ($sources as $src) {
    $f = $manager->read($src)->core()->first();
    $image->core()->add($f);
}
Defensive patterns

Strategy: try-catch

Validate before calling

foreach ($frames as $frame) {
    if (!$frame->native() instanceof \Imagick) {
        throw new InvalidArgumentException('frame native must be Imagick');
    }
    $frame->setDelay(max(0, $frame->delay()));
    $image->core()->add($frame);
}

Type guard

function isImagickFrame(FrameInterface $frame): bool
{
    return $frame->native() instanceof \Imagick;
}

Try / catch

use Intervention\Image\Exceptions\DriverException;

try {
    $image->core()->add($frame);
} catch (DriverException $e) {
    // frame stack is now possibly inconsistent: rebuild from sources
    throw new ImageBuildException('animation assembly failed', $e);
}

Prevention

When it happens

Trigger: Calling $image->core()->add($frame) or push($frame) (used when composing animations manually) where the frame's native() is not a usable Imagick single-frame object: it was already added to another stack and consumed, was cleared/destroyed, belongs to a different driver, or delay()/disposalMethod() return values Imagick rejects (e.g. negative delay).

Common situations: Building a GIF animation frame-by-frame and reusing the same source frame object twice; mixing GD-decoded frames into an Imagick core; adding frames after the target Imagick object was destroyed; passing a frame whose delay was computed as negative from bad timing data.

Related errors


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