PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception

Not a cell range address

Error message

Not a cell range address

What it means

While decoding a fixed 6-byte BIFF5 cell-range record (1-byte column fields, 2-byte row fields), first row > last row or first column > last column. Excel always stores ranges ordered, so an inverted range means the bytes are not really a range record (misaligned stream) or are corrupt.

Source

Thrown at src/PhpSpreadsheet/Reader/Xls/Biff5.php:32

     * section 2.5.14.
     */
    public static function readBIFF5CellRangeAddressFixed(string $subData): string
    {
        // offset: 0; size: 2; index to first row
        $fr = self::getUInt2d($subData, 0) + 1;

        // offset: 2; size: 2; index to last row
        $lr = self::getUInt2d($subData, 2) + 1;

        // offset: 4; size: 1; index to first column
        $fc = ord($subData[4]);

        // offset: 5; size: 1; index to last column
        $lc = ord($subData[5]);

        // check values
        if ($fr > $lr || $fc > $lc) {
            throw new ReaderException('Not a cell range address');
        }

        // column index to letter
        $fc = Coordinate::stringFromColumnIndex($fc + 1);
        $lc = Coordinate::stringFromColumnIndex($lc + 1);

        if ($fr == $lr && $fc == $lc) {
            return "$fc$fr";
        }

        return "$fc$fr:$lc$lr";
    }

    /**
     * Read BIFF5 cell range address list
     * section 2.5.15.
     *
     * @return array{size: int, cellRangeAddresses: string[]}

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Round-trip the file through Excel or LibreOffice (convert to .xlsx) so structures get rewritten cleanly
  2. Verify the file opens in Excel; if not, treat it as corrupt and obtain a fresh export
  3. If only values are needed, load with setReadDataOnly(true) so many range-bearing records are skipped
Defensive patterns

Strategy: try-catch

Try / catch

try {
    $spreadsheet = IOFactory::load($path);
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
    if (str_contains($e->getMessage(), 'Not a cell range address')) {
        // convert via LibreOffice to rebuild range records, then retry
    }
}

Prevention

When it happens

Trigger: Reading an .xls where an earlier record had a wrong length so subsequent records are parsed at the wrong offsets; genuinely damaged range structures in BIFF5 (Excel 5/95) files; 0xFFFF sentinel values in deleted ranges.

Common situations: Excel 5/95-era files with unusual or corrupt internal structures; files from archaic exporters; uploads that were truncated or byte-mangled.

Related errors


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