PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception
Cell range {$range} not known as protected.
Error message
Cell range {$range} not known as protected. What it means
Worksheet::unprotectCells() checks the exact normalized range string against the sheet's protectedCells map and throws when it is not a key. The input goes through trimSheetFromCellReference + validateCellOrCellRange (which expand a single cell to 'A1:A1'), but the resulting string must still equal the exact range used when protectCells() registered it.
Source
Thrown at src/PhpSpreadsheet/Worksheet/Worksheet.php:2046
}
/**
* Remove protection on a cell or cell range.
*
* @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|CellAddress|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 a CellAddress or AddressRange object.
*
* @return $this
*/
public function unprotectCells(AddressRange|CellAddress|int|string|array $range): static
{
$range = Functions::trimSheetFromCellReference(Validations::validateCellOrCellRange($range));
if (isset($this->protectedCells[$range])) {
unset($this->protectedCells[$range]);
} else {
throw new Exception('Cell range ' . $range . ' not known as protected.');
}
return $this;
}
/**
* Get protected cells.
*
* @return ProtectedRange[]
*/
public function getProtectedCellRanges(): array
{
return $this->protectedCells;
}
/**
* Get Autofilter.
*/View on GitHub (pinned to 65b080eef4)
Solutions
- Enumerate the real entries via $sheet->getProtectedCellRanges() (returns ProtectedRange objects — use their range string, e.g. $pr->getRange()) and unprotect exactly that
- Guard before the call: in_array($range, array_keys-ish list, true) or inspect getProtectedCellRanges() names/ranges
- If nothing is protected, skip the call rather than unprotecting speculatively
Example fix
// before
$sheet->unprotectCells('A1:B10'); // actual protected range was 'A1:B5' -> throws
// after
foreach ($sheet->getProtectedCellRanges() as $protectedRange) {
$sheet->unprotectCells($protectedRange->getRange()); // exact stored string
} Defensive patterns
Strategy: validation
Validate before calling
$known = array_map(
fn (ProtectedRange $pr) => $pr->getRange(),
$sheet->getProtectedCellRanges()
);
if (in_array($range, $known, true)) {
$sheet->unprotectCells($range);
} Try / catch
try {
$sheet->unprotectCells($range);
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
if (str_contains($e->getMessage(), 'not known as protected')) {
// nothing was protected under that exact range — skip
} else {
throw $e;
}
} Prevention
- Store the exact range string you passed to protectCells() if you must undo it later
- Source unprotect arguments from getProtectedCellRanges(), not from external bookkeeping
- Don't speculatively unprotect; check the protected set first
When it happens
Trigger: unprotectCells('A1:B10') when protection was registered as 'A1:B5' or never at all; unprotecting a differently formatted string (e.g. with '$' signs or lowercase) that does not match the stored key; calling unprotect after a fresh load where the protection lives on another sheet.
Common situations: Tracking protection ranges in your own DB/schema whose formatting drifts from what protectCells() stored; unprotecting guessed boundaries; sheet-level protection vs cell-range protection being confused.
Related errors
- Cell range {$range} not known as merged.
- Not a cell range address
- Not a cell range address
- CellRange array length must be 2 or 4
- Unsupported binary comparison operator
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/6b1ca7fc1b4774a8.
Report an issue: GitHub.