{"record":{"id":"562711f8437c2dd2","repo":"PHPOffice/PhpSpreadsheet","slug":"filename-is-an-invalid-gnumeric-file","errorCode":null,"errorMessage":"{filename} is an invalid Gnumeric file.","messagePattern":"(.+?) is an invalid Gnumeric file\\.","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Reader\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Reader/Gnumeric.php","lineNumber":168,"sourceCode":"            } elseif (self::matchXml($xml, 'Sheets')) {\n                //    break out of the loop once we've got our sheet names rather than parse the entire file\n                break;\n            }\n        }\n\n        return $worksheetNames;\n    }\n\n    /**\n     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).\n     *\n     * @return array<int, array{worksheetName: string, lastColumnLetter: string, lastColumnIndex: int, totalRows: int, totalColumns: int, sheetState: string}>\n     */\n    public function listWorksheetInfo(string $filename): array\n    {\n        File::assertFile($filename);\n        if (!$this->canRead($filename)) {\n            throw new Exception($filename . ' is an invalid Gnumeric file.');\n        }\n\n        $xml = new XMLReader();\n        $contents = $this->gzfileGetContents($filename);\n        $xml->xml($contents);\n        $xml->setParserProperty(2, true);\n\n        $worksheetInfo = [];\n        while ($xml->read()) {\n            if (self::matchXml($xml, 'Sheet')) {\n                $tmpInfo = [\n                    'worksheetName' => '',\n                    'lastColumnLetter' => 'A',\n                    'lastColumnIndex' => 0,\n                    'totalRows' => 0,\n                    'totalColumns' => 0,\n                    'sheetState' => Worksheet::SHEETSTATE_VISIBLE,\n                ];","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Reader/Gnumeric.php#L150-L186","documentation":"Gnumeric::listWorksheetInfo() validates the file with canRead() (gzip-compressed XML carrying the gnumeric namespace signature) before parsing sheet metadata. When the sniff fails, it throws this 'invalid Gnumeric file' exception before any XML is read.","triggerScenarios":"Calling listWorksheetInfo() with a plain XML/xlsx/ods file that merely has a .gnumeric extension; a truncated or corrupt gzip stream; a Gnumeric file from a version whose signature the reader does not recognize.","commonSituations":"User uploads accepted by extension instead of content; downloads interrupted so the .gz payload is incomplete; mixed-format ingest pipelines.","solutions":["Use IOFactory::identify($filename) to determine the real format and pick the matching reader","Verify the file actually opens in Gnumeric/LibreOffice; re-export if corrupt","For your own Gnumeric exports, validate canRead() right after writing as a smoke test"],"exampleFix":"// before\n$info = (new Gnumeric())->listWorksheetInfo('upload.gnumeric'); // actually XML -> throws\n\n// after\n$type = IOFactory::identify('upload.gnumeric');\n$reader = IOFactory::createReader($type);\n$info = $reader->listWorksheetInfo('upload.gnumeric');","handlingStrategy":"validation","validationCode":"$reader = new Gnumeric();\nif (!$reader->canRead($filename)) {\n    throw new RuntimeException('Not a readable Gnumeric file: ' . $filename);\n}\n$info = $reader->listWorksheetInfo($filename);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Sniff with canRead() before metadata queries","Use IOFactory::identify() for unknown uploads instead of hardcoding the Gnumeric reader","Treat 'invalid Gnumeric file' as a routing problem first — check the real format, then the file integrity"],"tags":["gnumeric","format-detection","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"}