PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception
Rows can only be inserted before at least row 1.
Error message
Rows can only be inserted before at least row 1.
What it means
insertNewRowBefore(int $before, int $numberOfRows = 1) shifts existing rows down and inserts blanks before row $before via ReferenceHelper. Spreadsheet rows are 1-indexed, so the method requires $before >= 1 and throws immediately for 0 or negative values before any shifting work starts.
Source
Thrown at src/PhpSpreadsheet/Worksheet/Worksheet.php:2542
return $this;
}
/**
* Insert a new row, updating all possible related data.
*
* @param int $before Insert before this row number
* @param int $numberOfRows Number of new rows to insert
*
* @return $this
*/
public function insertNewRowBefore(int $before, int $numberOfRows = 1): static
{
if ($before >= 1) {
$objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore('A' . $before, 0, $numberOfRows, $this);
} else {
throw new Exception('Rows can only be inserted before at least row 1.');
}
return $this;
}
/**
* Insert a new column, updating all possible related data.
*
* @param string $before Insert before this column Name, eg: 'A'
* @param int $numberOfColumns Number of new columns to insert
*
* @return $this
*/
public function insertNewColumnBefore(string $before, int $numberOfColumns = 1): static
{
if (!is_numeric($before)) {
$objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore($before . '1', $numberOfColumns, 0, $this);View on GitHub (pinned to 65b080eef4)
Solutions
- Pass a row number >= 1; to insert above the first row use insertNewRowBefore(1).
- Convert 0-based positions at the boundary: insertNewRowBefore($zeroBasedIndex + 1, $count).
- Clamp computed values: $before = max(1, $computed);
- Audit loops that build row numbers from array keys; array_values($data) plus +1 removes the trap.
Example fix
// before
foreach ($data as $offset => $row) {
$sheet->insertNewRowBefore($offset, 1); // $offset starts at 0 -> throws
}
// after
foreach (array_values($data) as $offset => $row) {
$sheet->insertNewRowBefore($offset + 1, 1);
} Defensive patterns
Strategy: validation
Validate before calling
$insertAt = count($templateRows) + 1; // spreadsheet rows are 1-based $sheet->insertNewRowBefore(max(1, $insertAt), 2);
Type guard
/** Spreadsheet rows are 1-based: row 1 is the first row. */
function isPositiveRow(int $row): bool
{
return $row >= 1;
} Prevention
- Treat every worksheet row/column argument as 1-based.
- Convert array keys with + 1 exactly where data becomes spreadsheet coordinates.
- Clamp computed insertion points with max(1, $n) instead of trusting upstream math.
When it happens
Trigger: insertNewRowBefore(0) or insertNewRowBefore(-3); a 0-based array index (foreach ($rows as $i => ...) with $i starting at 0) passed as the row number; offset arithmetic such as insertNewRowBefore($rowNumber - 1) evaluating to 0 when $rowNumber is 1.
Common situations: Classic zero-based vs one-base confusion when mapping PHP array positions to spreadsheet rows; importers computing an insertion point from CSV line numbers or database row offsets; refactors where a loop counter starting at 0 leaks into worksheet API calls.
Related errors
- Rows to be deleted should at least start from row 1.
- Freeze pane can not be set on a range of cells.
- Column references should not be numeric.
- Columns can only be inserted before at least column A (1).
- Columns to be deleted should at least start from column A (1
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/05a30356b4c57905.
Report an issue: GitHub.