PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

In "IterateOnlyExistingCells" mode and Cell does not exist

Error message

In "IterateOnlyExistingCells" mode and Cell does not exist

What it means

ColumnCellIterator::seek() refuses to move the row pointer to a row whose cell does not exist when the iterator runs in iterate-only-existing-cells mode. That mode promises never to yield blank cells, so seeking to a void cell is an error rather than a silent skip.

Source

Thrown at src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php:97

        $this->adjustForExistingOnlyRange();

        return $this;
    }

    /**
     * Set the row pointer to the selected row.
     *
     * @param int $row The row number to set the current pointer at
     *
     * @return $this
     */
    public function seek(int $row = 1): static
    {
        if (
            $this->onlyExistingCells
            && (!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->columnIndex) . $row))
        ) {
            throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
        }
        if (($row < $this->startRow) || ($row > $this->endRow)) {
            throw new PhpSpreadsheetException("Row $row is out of range ({$this->startRow} - {$this->endRow})");
        }
        $this->currentRow = $row;

        return $this;
    }

    /**
     * Rewind the iterator to the starting row.
     */
    public function rewind(): void
    {
        $this->currentRow = $this->startRow;
    }

    /**

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Turn off the mode ($iterator->setIterateOnlyExistingCells(false)) if you need to seek into gaps
  2. Check $sheet->getCellCollection()->has($coord) before seeking
  3. Iterate with foreach, which skips missing cells correctly in this mode

Example fix

// before
$cellIterator->setIterateOnlyExistingCells(true);
$cellIterator->seek('7'); // cell A7 does not exist

// after
$coord = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($cellIterator->key() ?: 1) . '7';
if ($sheet->getCellCollection()->has($coord)) {
    $cellIterator->seek(7);
}
Defensive patterns

Strategy: validation

Validate before calling

$coord = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($columnIndex) . $row;
if (!$sheet->getCellCollection()->has($coord)) {
    throw new OutOfBoundsException("Cell $coord does not exist; cannot seek in only-existing-cells mode");
}
$cellIterator->seek($row);

Type guard

function cellExists(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet, string $coord): bool
{
    return $sheet->getCellCollection()->has($coord);
}

Try / catch

try {
    $cellIterator->seek($row);
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
    $cellIterator->setIterateOnlyExistingCells(false);
    $cellIterator->seek($row);
}

Prevention

When it happens

Trigger: $sheet->getColumnIterator('A')->current() ... more precisely: creating ColumnCellIterator with setIterateOnlyExistingCells(true) then seek($row) where the cell at (column,row) was never created.

Common situations: Sparse sheets where code seeks to a row number computed from data that has gaps; combining setIterateOnlyExistingCells(true) with random-access seek() instead of foreach iteration.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/043e3cc71fba3ab4. Report an issue: GitHub.