{"record":{"id":"be94c2d064c52f26","repo":"PHPOffice/PhpSpreadsheet","slug":"columns-can-only-be-inserted-before-at-least-colum","errorCode":null,"errorMessage":"Columns can only be inserted before at least column A (1).","messagePattern":"Columns can only be inserted before at least column A \\(1\\)\\.","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Worksheet/Worksheet.php","lineNumber":2582,"sourceCode":"\n        return $this;\n    }\n\n    /**\n     * Insert a new column, updating all possible related data.\n     *\n     * @param int $beforeColumnIndex Insert before this column ID (numeric column coordinate of the cell)\n     * @param int $numberOfColumns Number of new columns to insert\n     *\n     * @return $this\n     */\n    public function insertNewColumnBeforeByIndex(int $beforeColumnIndex, int $numberOfColumns = 1): static\n    {\n        if ($beforeColumnIndex >= 1) {\n            return $this->insertNewColumnBefore(Coordinate::stringFromColumnIndex($beforeColumnIndex), $numberOfColumns);\n        }\n\n        throw new Exception('Columns can only be inserted before at least column A (1).');\n    }\n\n    /**\n     * Delete a row, updating all possible related data.\n     *\n     * @param int $row Remove rows, starting with this row number\n     * @param int $numberOfRows Number of rows to remove\n     *\n     * @return $this\n     */\n    public function removeRow(int $row, int $numberOfRows = 1): static\n    {\n        if ($row < 1) {\n            throw new Exception('Rows to be deleted should at least start from row 1.');\n        }\n        if ($numberOfRows === 0) {\n            return $this;\n        }","sourceCodeStart":2564,"sourceCodeEnd":2600,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Worksheet/Worksheet.php#L2564-L2600","documentation":"insertNewColumnBeforeByIndex(int $beforeColumnIndex, int $numberOfColumns = 1) converts a 1-based column index to its letter and delegates to insertNewColumnBefore(). Column A is index 1, so an index of 0 or negative is rejected before the conversion runs.","triggerScenarios":"insertNewColumnBeforeByIndex(0); a 0-based column loop counter passed straight through; index arithmetic such as $col - 1 hitting 0 at the first column.","commonSituations":"Looping for ($col = 0; $col < $n; ++$col) over grid data; mapping 0-based array columns to spreadsheet columns without adding 1.","solutions":["Pass >= 1 (A = 1, B = 2, Z = 26, AA = 27).","Convert 0-based loops: insertNewColumnBeforeByIndex($i + 1).","Clamp computed indexes with max(1, $index)."],"exampleFix":"// before\nfor ($col = 0; $col < 5; ++$col) {\n    $sheet->insertNewColumnBeforeByIndex($col); // throws on first iteration\n}\n\n// after\nfor ($col = 1; $col <= 5; ++$col) {\n    $sheet->insertNewColumnBeforeByIndex($col);\n}","handlingStrategy":"type-guard","validationCode":"for ($col = 1; $col <= $maxCol; ++$col) { // column A is index 1\n    $sheet->insertNewColumnBeforeByIndex($col);\n}","typeGuard":"/** Column indexes are 1-based: A = 1, B = 2, ... */\nfunction isPositiveColumnIndex(int $index): bool\n{\n    return $index >= 1;\n}","tryCatchPattern":null,"preventionTips":["Start column loops at 1, not 0.","Clamp computed indexes with max(1, $index).","Prefer ...ByIndex APIs when converting user-facing column numbers."],"tags":["phpspreadsheet","worksheet","insert-column","column-index","argument-validation"],"backgroundTag":"off-by-one-index","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}