{"record":{"id":"6c7c556a42025f70","repo":"PHPOffice/PhpSpreadsheet","slug":"row-and-column-ids-must-be-positive-integer-values","errorCode":null,"errorMessage":"Row and Column Ids must be positive integer values","messagePattern":"Row and Column Ids must be positive integer values","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Cell/CellAddress.php","lineNumber":40,"sourceCode":"    {\n        $this->cellAddress = str_replace('$', '', $cellAddress);\n        [$this->columnId, $this->rowId, $this->columnName] = Coordinate::indexesFromString($this->cellAddress);\n        $this->worksheet = $worksheet;\n    }\n\n    public function __destruct()\n    {\n        unset($this->worksheet);\n    }\n\n    /**\n     * @phpstan-assert int|numeric-string $columnId\n     * @phpstan-assert int|numeric-string $rowId\n     */\n    private static function validateColumnAndRow(int|string $columnId, int|string $rowId): void\n    {\n        if (!is_numeric($columnId) || $columnId <= 0 || !is_numeric($rowId) || $rowId <= 0) {\n            throw new Exception('Row and Column Ids must be positive integer values');\n        }\n    }\n\n    public static function fromColumnAndRow(int|string $columnId, int|string $rowId, ?Worksheet $worksheet = null): self\n    {\n        self::validateColumnAndRow($columnId, $rowId);\n\n        return new self(Coordinate::stringFromColumnIndex($columnId) . $rowId, $worksheet);\n    }\n\n    /** @param array<int, int> $array */\n    public static function fromColumnRowArray(array $array, ?Worksheet $worksheet = null): self\n    {\n        [$columnId, $rowId] = $array;\n\n        return self::fromColumnAndRow($columnId, $rowId, $worksheet);\n    }\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Cell/CellAddress.php#L22-L58","documentation":"CellAddress::fromColumnAndRow()/fromColumnRowArray() validate both ids via validateColumnAndRow(): each must be numeric and strictly greater than zero. Columns and rows in a spreadsheet are 1-based, so 0, negatives, and non-numeric strings (letters are not valid here - they belong in coordinate strings like 'A1') all throw before the address is built.","triggerScenarios":"fromColumnAndRow(0, 5) from a loop that starts at 0; fromColumnAndRow(-1, 2) from arithmetic that underflows; fromColumnAndRow('A', 1) confusing column letters with column indexes; passing array keys (0-based) straight through.","commonSituations":"Mapping 0-based array iterations or CSV row indexes directly onto spreadsheet columns; off-by-one bugs after refactoring loops; generators yielding 0-based keys fed into address builders.","solutions":["Start loops at 1: for ($col = 1; $col <= $maxCol; ++$col)","Clamp inputs: max(1, (int) $col), max(1, (int) $row)","If you hold letters, build the address string and use CellAddress::fromCellAddress('A1') instead","Validate early and raise your own error naming the offending index"],"exampleFix":"// before\n$address = CellAddress::fromColumnAndRow($arrayKey, $rowIndex); // $arrayKey starts at 0 -> throws\n\n// after\n$address = CellAddress::fromColumnAndRow($arrayKey + 1, $rowIndex + 1); // translate 0-based to 1-based","handlingStrategy":"validation","validationCode":"$col = max(1, (int) $columnId);\n$row = max(1, (int) $rowId);\n$address = CellAddress::fromColumnAndRow($col, $row);","typeGuard":"function isValidColumnRowIndex(int|string $id): bool\n{\n    return is_numeric($id) && $id > 0;\n}","tryCatchPattern":"null","preventionTips":["Remember spreadsheet columns and rows are 1-based; translate 0-based indexes explicitly (+1)","Start loops at 1 and use <= for the upper bound","Pass column letters as coordinate strings ('A1') via CellAddress::fromCellAddress(), never to fromColumnAndRow()","Clamp untrusted indexes with max(1, ...) at the input boundary"],"tags":["phpspreadsheet","cell-address","coordinate","argument-validation","off-by-one"],"backgroundTag":"invalid-cell-coordinate","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}