PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Cell range {$range} not known as merged.

Error message

Cell range {$range} not known as merged.

What it means

Worksheet::unmergeCells() looks the exact normalized range string up in the sheet's merged-cells map and throws when it is absent. Unlike mergeCells() it does not normalize bounds or expand single cells, so the string must byte-for-byte equal a stored entry (which mergeCells stores in normalized 'A1:B2' form: colon present, top-left first).

Source

Thrown at src/PhpSpreadsheet/Worksheet/Worksheet.php:1973

    /**
     * Remove merge on a cell range.
     *
     * @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $range A simple string containing a Cell range like 'A1:E10'
     *              or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
     *              or an AddressRange.
     *
     * @return $this
     */
    public function unmergeCells(AddressRange|string|array $range): static
    {
        $range = Functions::trimSheetFromCellReference(Validations::validateCellRange($range));

        if (str_contains($range, ':')) {
            if (isset($this->mergeCells[$range])) {
                unset($this->mergeCells[$range]);
            } else {
                throw new Exception('Cell range ' . $range . ' not known as merged.');
            }
        } else {
            throw new Exception('Merge can only be removed from a range of cells.');
        }

        return $this;
    }

    /**
     * Get merge cells array.
     *
     * @return string[]
     */
    public function getMergeCells(): array
    {
        return $this->mergeCells;
    }

View on GitHub (pinned to 65b080eef4)

Solutions

  1. List the real merges first: $merges = $sheet->getMergeCells(); and pass one of those exact strings to unmergeCells()
  2. To unmerge 'the block containing A1', find the containing entry: foreach ($sheet->getMergeCells() as $m) { if (Coordinate::coordinateIsInside? — check bounds) unmergeCells($m); } using rangeBoundaries containment
  3. Guard with in_array($range, $sheet->getMergeCells(), true) before calling

Example fix

// before
$sheet->unmergeCells('A1:C3'); // actual merge was 'A1:B2' -> throws

// after
$target = 'A1:C3';
if (in_array($target, $sheet->getMergeCells(), true)) {
    $sheet->unmergeCells($target);
} else {
    foreach ($sheet->getMergeCells() as $merge) {
        if (str_contains($merge, 'A1:') || str_starts_with($merge, 'A1')) {
            $sheet->unmergeCells($merge);
        }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (in_array($range, $sheet->getMergeCells(), true)) {
    $sheet->unmergeCells($range);
} else {
    // pick the exact stored string from getMergeCells() instead
}

Try / catch

try {
    $sheet->unmergeCells($range);
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
    if (str_contains($e->getMessage(), 'not known as merged')) {
        // range was never merged — nothing to do
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: unmergeCells('A1:C3') when the actual merge is 'A1:B2'; unmerging before any mergeCells() call on that range; passing reversed bounds 'C3:A1' or a lowercase variant of a stored merge.

Common situations: Unmerging a guessed/remembered range instead of the exact one; loading third-party files where merge boundaries differ from expectations; unmerging a sub-block assumed to be independently merged.

Related errors


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