PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception
Freeze pane can not be set on a range of cells.
Error message
Freeze pane can not be set on a range of cells.
What it means
Worksheet::freezePane() defines a freeze split at a single cell coordinate, with an optional second argument for the top-left cell of the scrollable pane. A frozen pane is a split point, not an area, so after validating the argument and trimming any sheet prefix the method rejects anything that Coordinate::coordinateIsRange() recognizes as a range (any string containing ':'). Throwing here stops writers from serializing pane XML that Excel would treat as corrupt.
Source
Thrown at src/PhpSpreadsheet/Worksheet/Worksheet.php:2364
* @param null|array{0: int, 1: int}|CellAddress|string $topLeftCell default position of the right bottom pane
* Coordinate of the cell as a string, eg: 'C5'; or as an array of [$columnIndex, $row] (e.g. [3, 5]),
* or a CellAddress object.
*
* @return $this
*/
public function freezePane(null|CellAddress|string|array $coordinate, null|CellAddress|string|array $topLeftCell = null, bool $frozenSplit = false): static
{
$this->panes = [
'bottomRight' => null,
'bottomLeft' => null,
'topRight' => null,
'topLeft' => null,
];
$cellAddress = ($coordinate !== null)
? Functions::trimSheetFromCellReference(Validations::validateCellAddress($coordinate))
: null;
if ($cellAddress !== null && Coordinate::coordinateIsRange($cellAddress)) {
throw new Exception('Freeze pane can not be set on a range of cells.');
}
$topLeftCell = ($topLeftCell !== null)
? Functions::trimSheetFromCellReference(Validations::validateCellAddress($topLeftCell))
: null;
if ($cellAddress !== null && $topLeftCell === null) {
$coordinate = Coordinate::coordinateFromString($cellAddress);
$topLeftCell = $coordinate[0] . $coordinate[1];
}
$topLeftCell = "$topLeftCell";
$this->paneTopLeftCell = $topLeftCell;
$this->freezePane = $cellAddress;
$this->topLeftCell = $topLeftCell;
if ($cellAddress === null) {
$this->paneState = '';
$this->xSplit = $this->ySplit = 0;View on GitHub (pinned to 65b080eef4)
Solutions
- Pass a single cell: freezePane('A2') freezes the top row, freezePane('B1') freezes column A, freezePane('B2') freezes both.
- If you only have a range string, use its first cell as the split point: [$first] = explode(':', $range, 2); freezePane($first).
- Remember the second parameter is the scrollable pane's top-left cell (e.g. freezePane('B2', 'C3')), not the second bound of an area.
- Validate free-text input with Coordinate::coordinateIsRange() before calling any worksheet geometry method.
Example fix
// before
$used = $sheet->calculateWorksheetDimension(); // e.g. A1:F20
$sheet->freezePane($used); // throws: range
// after
$sheet->freezePane('A2'); // freeze the top row only
// keep rows 1-3 and columns A-B visible:
$sheet->freezePane('C4'); Defensive patterns
Strategy: validation
Validate before calling
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
$coord = 'A1:F10';
if (Coordinate::coordinateIsRange($coord)) {
// a freeze pane is one split cell, not an area
[$coord] = explode(':', $coord, 2);
}
$sheet->freezePane($coord); Type guard
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
/** True only for a single relative cell address like 'C5'. */
function isSingleCellCoordinate(string $address): bool
{
return $address !== ''
&& !str_contains($address, '$')
&& !Coordinate::coordinateIsRange($address);
} Prevention
- Never feed calculateWorksheetDimension() or any 'A1:B2' string into freezePane(); it takes exactly one cell.
- Treat the first argument as 'the first unfrozen cell': 'B2' keeps row 1 and column A visible.
- Validate free-text config or user input with Coordinate::coordinateIsRange() before passing it to worksheet geometry methods.
When it happens
Trigger: Calling $sheet->freezePane('A1:F10') or freezePane('B2:D5') with any colon-containing string; reusing a used-range string such as the result of calculateWorksheetDimension() (which returns something like 'A1:G20'); forwarding a user- or config-supplied 'range to freeze' verbatim.
Common situations: Developers confuse 'freeze the header area' with 'pass the header range' and pass 'A1:C1' instead of 'A2'. Also seen when migrating older PHPExcel code that reused one range variable for styling, autofilter and freezing, and when a UI accepts a range that is forwarded without normalization.
Related errors
- Invalid Worksheet for specified Range
- Rows can only be inserted before at least row 1.
- Column references should not be numeric.
- Columns can only be inserted before at least column A (1).
- Rows to be deleted should at least start from row 1.
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/a3db1d50109bce32.
Report an issue: GitHub.