PHPOffice/PhpSpreadsheet · error · ReaderException

$filename is an Invalid Spreadsheet file.

Error message

$filename is an Invalid Spreadsheet file.

What it means

Before parsing, the Csv reader runs its canRead() heuristic (recognizable delimiter structure such as commas/semicolons/tabs across lines). openFileOrMemory() throws this exception when that sniff fails, i.e. the content does not look like delimited text at all.

Source

Thrown at src/PhpSpreadsheet/Reader/Csv.php:291

    /**
     * Loads Spreadsheet from string.
     */
    public function loadSpreadsheetFromString(string $contents): Spreadsheet
    {
        $spreadsheet = $this->newSpreadsheet();
        $spreadsheet->setValueBinder($this->valueBinder);

        // Load into this instance
        return $this->loadStringOrFile('data://text/plain,' . urlencode($contents), $spreadsheet, true);
    }

    private function openFileOrMemory(string $filename): void
    {
        // Open file
        $fhandle = $this->canRead($filename);
        if (!$fhandle) {
            throw new ReaderException($filename . ' is an Invalid Spreadsheet file.');
        }
        if ($this->inputEncoding === 'UTF-8') {
            $encoding = self::guessEncodingBom($filename);
            if ($encoding !== '') {
                $this->inputEncoding = $encoding;
            }
        }
        if ($this->inputEncoding === self::GUESS_ENCODING) {
            $this->inputEncoding = self::guessEncoding($filename, $this->fallbackEncoding);
        }
        $this->openFile($filename);
        if ($this->inputEncoding !== 'UTF-8') {
            $this->convertNonUtf8($filename);
        }
    }

    protected function convertNonUtf8(string $filename): void
    {

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Detect the real format first with IOFactory::identify($file) and instantiate the matching reader
  2. If the file really is CSV, inspect it: ensure it contains recognizable delimiter lines and decodable text; re-export from the source system if corrupt
  3. For non-standard delimiters, configure the Csv reader's delimiter settings before loading so the content is parsed as intended

Example fix

// before
$spreadsheet = (new Csv())->load($uploadPath); // upload is actually xlsx renamed .csv -> throws

// after
$type = IOFactory::identify($uploadPath);
$reader = IOFactory::createReader($type);
$spreadsheet = $reader->load($uploadPath);
Defensive patterns

Strategy: validation

Validate before calling

$reader = new Csv();
if (!$reader->canRead($uploadPath)) {
    throw new RuntimeException('File does not look like a delimited CSV');
}
$spreadsheet = $reader->load($uploadPath);

Try / catch

try {
    $spreadsheet = (new Csv())->load($path);
} catch (ReaderException $e) {
    if (str_contains($e->getMessage(), 'Invalid Spreadsheet file')) {
        $spreadsheet = IOFactory::load($path); // retry with the detected real reader
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: (new Csv())->load('notes.txt') where the file has no delimiter lines; binary content or a real .xlsx/.ods renamed to .csv; a single-column file with no delimiters anywhere; content garbled by wrong encoding so delimiter detection fails.

Common situations: User uploads where the original spreadsheet was merely renamed to .csv; automated imports pulling from endpoints that returned HTML error pages or JSON instead of CSV; ERP exports with unusual delimiters never configured on the reader.

Related errors


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