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
- Detect the real format first with IOFactory::identify($file) and instantiate the matching reader
- 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
- 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
- Route uploads through IOFactory::identify() instead of trusting the .csv extension
- Validate a sample of the content (delimiter presence, decodable text) before importing
- Log rejected samples so mislabeled uploads surface early in support queues
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
- {filename} is an invalid Gnumeric file.
- {filename} is an Invalid HTML file.
- {filename} is an Invalid SYLK file.
- Could not open file {filename} for reading.
- Unable to get contents of $filename
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/17feba5023b312ff.
Report an issue: GitHub.