{"record":{"id":"17feba5023b312ff","repo":"PHPOffice/PhpSpreadsheet","slug":"filename-is-an-invalid-spreadsheet-file","errorCode":null,"errorMessage":"$filename is an Invalid Spreadsheet file.","messagePattern":"\\$filename is an Invalid Spreadsheet file\\.","errorType":"exception","errorClass":"ReaderException","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Reader/Csv.php","lineNumber":291,"sourceCode":"\n    /**\n     * Loads Spreadsheet from string.\n     */\n    public function loadSpreadsheetFromString(string $contents): Spreadsheet\n    {\n        $spreadsheet = $this->newSpreadsheet();\n        $spreadsheet->setValueBinder($this->valueBinder);\n\n        // Load into this instance\n        return $this->loadStringOrFile('data://text/plain,' . urlencode($contents), $spreadsheet, true);\n    }\n\n    private function openFileOrMemory(string $filename): void\n    {\n        // Open file\n        $fhandle = $this->canRead($filename);\n        if (!$fhandle) {\n            throw new ReaderException($filename . ' is an Invalid Spreadsheet file.');\n        }\n        if ($this->inputEncoding === 'UTF-8') {\n            $encoding = self::guessEncodingBom($filename);\n            if ($encoding !== '') {\n                $this->inputEncoding = $encoding;\n            }\n        }\n        if ($this->inputEncoding === self::GUESS_ENCODING) {\n            $this->inputEncoding = self::guessEncoding($filename, $this->fallbackEncoding);\n        }\n        $this->openFile($filename);\n        if ($this->inputEncoding !== 'UTF-8') {\n            $this->convertNonUtf8($filename);\n        }\n    }\n\n    protected function convertNonUtf8(string $filename): void\n    {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Reader/Csv.php#L273-L309","documentation":"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.","triggerScenarios":"(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.","commonSituations":"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.","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"],"exampleFix":"// before\n$spreadsheet = (new Csv())->load($uploadPath); // upload is actually xlsx renamed .csv -> throws\n\n// after\n$type = IOFactory::identify($uploadPath);\n$reader = IOFactory::createReader($type);\n$spreadsheet = $reader->load($uploadPath);","handlingStrategy":"validation","validationCode":"$reader = new Csv();\nif (!$reader->canRead($uploadPath)) {\n    throw new RuntimeException('File does not look like a delimited CSV');\n}\n$spreadsheet = $reader->load($uploadPath);","typeGuard":null,"tryCatchPattern":"try {\n    $spreadsheet = (new Csv())->load($path);\n} catch (ReaderException $e) {\n    if (str_contains($e->getMessage(), 'Invalid Spreadsheet file')) {\n        $spreadsheet = IOFactory::load($path); // retry with the detected real reader\n    } else {\n        throw $e;\n    }\n}","preventionTips":["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"],"tags":["csv","format-detection","upload","file-validation"],"backgroundTag":"file-format-not-recognized","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}