{"record":{"id":"df3d2c32a4d716d7","repo":"PHPOffice/PhpSpreadsheet","slug":"only-cell-ranges-may-be-passed-to-this-method","errorCode":null,"errorMessage":"Only cell ranges may be passed to this method.","messagePattern":"Only cell ranges may be passed to this method\\.","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/ReferenceHelper.php","lineNumber":1137,"sourceCode":"             *      them with a #REF!\n             */\n            $formula = $definedName->getValue();\n            $formula = $this->updateFormulaReferences($formula, $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true);\n            $definedName->setValue($formula);\n        }\n    }\n\n    /**\n     * Update cell range.\n     *\n     * @param string $cellRange Cell range    (e.g. 'B2:D4', 'B:C' or '2:3')\n     *\n     * @return string Updated cell range\n     */\n    private function updateCellRange(string $cellRange = 'A1:A1', bool $includeAbsoluteReferences = false, bool $onlyAbsoluteReferences = false): string\n    {\n        if (!Coordinate::coordinateIsRange($cellRange)) {\n            throw new Exception('Only cell ranges may be passed to this method.');\n        }\n\n        // Update range\n        $range = Coordinate::splitRange($cellRange);\n        $ic = count($range);\n        for ($i = 0; $i < $ic; ++$i) {\n            $jc = count($range[$i]);\n            for ($j = 0; $j < $jc; ++$j) {\n                /** @var CellReferenceHelper */\n                $cellReferenceHelper = $this->cellReferenceHelper;\n                if (ctype_alpha($range[$i][$j])) {\n                    $range[$i][$j] = Coordinate::coordinateFromString(\n                        $cellReferenceHelper->updateCellReference($range[$i][$j] . '1', $includeAbsoluteReferences, $onlyAbsoluteReferences, null)\n                    )[0];\n                } elseif (ctype_digit($range[$i][$j])) {\n                    $range[$i][$j] = Coordinate::coordinateFromString(\n                        $cellReferenceHelper->updateCellReference('A' . $range[$i][$j], $includeAbsoluteReferences, $onlyAbsoluteReferences, null)\n                    )[1];","sourceCodeStart":1119,"sourceCodeEnd":1155,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/ReferenceHelper.php#L1119-L1155","documentation":"updateCellRange() is a private ReferenceHelper helper (the engine behind insertNewBefore/insertRows/removeColumn) that only accepts strings Coordinate::coordinateIsRange() classifies as a range, i.e. containing a ':' separator. Its only caller (updateCellReference at src/PhpSpreadsheet/ReferenceHelper.php:1048) branches single-cell references away first, so hitting this throw means reference metadata inside the workbook degraded to a non-range form mid-processing. It is effectively an internal invariant guard, not a public API validation.","triggerScenarios":"Running $sheet->insertNewBefore(), insertRows(), removeColumn(), or updateNamedRanges() on a workbook whose defined names, print areas, or data-validation ranges hold malformed values (e.g. a stored range that collapses to a single cell after earlier mutations); invoking the private method through reflection or a forked copy of the class.","commonSituations":"Workbooks loaded from untrusted/corrupt sources; repeated insert/delete cycles that shrink a named range to one cell and leave stale metadata; bugs in older PhpSpreadsheet releases around named-range adjustment.","solutions":["Update to the latest PhpSpreadsheet patch release; several insert/delete reference-adjustment bugs have been fixed over time","Inspect $spreadsheet->getDefinedNames() and getPrintArea() for each sheet; remove or rewrite malformed/single-cell entries before inserting rows","Reproduce with a minimal workbook and report upstream, since this guard should be unreachable through the public API","Do not call ReferenceHelper internals via reflection"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before insert/delete, audit range-like metadata for non-range values\nforeach ($spreadsheet->getDefinedNames() as $name => $def) {\n    $value = $def->getValue();\n    if ($value !== null && !str_contains($value, ':') && preg_match('/^[A-Z]+[0-9]+$/i', $value)) {\n        // single-cell stored where range expected: normalize or drop\n        $spreadsheet->removeNamedRange($name);\n    }\n}","typeGuard":"function isCellRangeString(string $ref): bool\n{\n    return \\PhpOffice\\PhpSpreadsheet\\Cell\\Coordinate::coordinateIsRange($ref);\n}","tryCatchPattern":"try {\n    $sheet->insertNewBefore('A1', 0, 1);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    if (str_contains($e->getMessage(), 'Only cell ranges')) {\n        // corrupt reference metadata: report the workbook, skip structural edits\n    }\n}","preventionTips":["Prefer insertRows()/removeRows() wrappers over raw insertNewBefore on suspect workbooks","Sanitize defined names and print areas after loading untrusted files","Keep PhpSpreadsheet current to get insert/delete adjustment fixes","Never reach into ReferenceHelper privates via reflection"],"tags":["internal-invariant","cell-references","insert-delete-rows","named-ranges"],"backgroundTag":"invalid-range-argument","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}