PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Could not clone image resource

Error message

Could not clone image resource

What it means

MemoryDrawing holds a live GD image resource. When it is cloned — directly, or indirectly via clone $worksheet, Worksheet::copy(), or copying a whole spreadsheet — cloneResource() rebuilds the canvas with imagecreatetruecolor() for truecolor images. If GD returns false (zero width/height from a broken source, or memory exhausted allocating a large bitmap) it throws 'Could not clone image resource'.

Source

Thrown at src/PhpSpreadsheet/Worksheet/MemoryDrawing.php:89

    public function __clone()
    {
        parent::__clone();
        $this->cloneResource();
    }

    private function cloneResource(): void
    {
        if (!$this->imageResource) {
            return;
        }

        $width = (int) imagesx($this->imageResource);
        $height = (int) imagesy($this->imageResource);

        if (imageistruecolor($this->imageResource)) {
            $clone = imagecreatetruecolor($width, $height);
            if (!$clone) {
                throw new Exception('Could not clone image resource');
            }

            imagealphablending($clone, false);
            imagesavealpha($clone, true);
        } else {
            $clone = imagecreate($width, $height);
            if (!$clone) {
                throw new Exception('Could not clone image resource');
            }

            // If the image has transparency...
            $transparent = imagecolortransparent($this->imageResource);
            if ($transparent >= 0) {
                // Starting with Php8.0, next function throws rather than return false
                $rgb = imagecolorsforindex($this->imageResource, $transparent);

                imagesavealpha($clone, true);
                $color = imagecolorallocatealpha($clone, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Raise PHP memory_limit to cover roughly width*height*8 bytes for the largest drawing.
  2. Avoid cloning the drawing: rebuild it from its rendered bytes with MemoryDrawing::fromString($drawing->getContents()).
  3. Validate sources (getimagesize / non-zero imagesx-imagesy) before they become MemoryDrawings so clones never see 0-size resources.

Example fix

// before
$newSheet = clone $sheet; // contains a MemoryDrawing -> Could not clone image resource

// after
$bytes = $drawing->getContents();
$drawing2 = MemoryDrawing::fromString($bytes); // fresh resource, no GD clone
Defensive patterns

Strategy: try-catch

Validate before calling

$gd = $memoryDrawing->getImageResource();
if ($gd === null || imagesx($gd) < 1 || imagesy($gd) < 1) {
    $memoryDrawing = MemoryDrawing::fromString($memoryDrawing->getContents()); // rebuild a valid resource
}
// cloning now has non-zero dimensions to work with

Try / catch

try {
    $copy = clone $worksheet; // or $sheet->copy()
} catch (PhpSpreadsheetException $e) {
    // GD could not allocate the clone canvas: free memory or rebuild the drawing
    $bytes = $memoryDrawing->getContents();
    // re-attach as MemoryDrawing::fromString($bytes), then retry the copy
}

Prevention

When it happens

Trigger: clone $worksheet containing a MemoryDrawing; template flows calling $sheet->copy() once per data set; a GD resource whose width or height is 0 because the image partially decoded; a 6000x6000 truecolor canvas exceeding memory_limit during allocation.

Common situations: Report generators duplicating a styled template sheet; memory_limit pressure because cloning doubles each bitmap (~4 bytes/pixel twice); MemoryDrawing objects built from truncated strings.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/05768c3c1ff802e9. Report an issue: GitHub.