PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception
Cannot load invalid XML ${fileOrString}: ${filename}
Error message
Cannot load invalid XML ${fileOrString}: ${filename} What it means
trySimpleXMLLoadStringPrivate() wraps simplexml_load_string plus the security-scanner scan in a try/catch and rethrows with this message, chaining the original Throwable. It fires when the bytes are not well-formed XML, when the XML scanner rejects the content, or on an empty path; the message says whether a 'file' or 'string' was being loaded.
Source
Thrown at src/PhpSpreadsheet/Reader/Xml.php:145
$continue = true;
if ($data === '' && $fileOrString === 'file') {
if ($filename === '') {
$this->xmlFailMessage = 'Cannot load empty path';
$continue = false;
} else {
$datax = @file_get_contents($filename);
$data = $datax ?: '';
$continue = $datax !== false;
}
}
if ($continue) {
$xml = @simplexml_load_string(
$this->getSecurityScannerOrThrow()
->scan($data)
);
}
} catch (Throwable $e) {
throw new Exception($this->xmlFailMessage, 0, $e);
}
$this->fileContents = '';
return $xml;
}
/**
* Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object.
*
* @return string[]
*/
public function listWorksheetNames(string $filename): array
{
File::assertFile($filename);
if (!$this->canRead($filename)) {
throw new Exception($filename . ' is an Invalid Spreadsheet file.');
}
View on GitHub (pinned to 65b080eef4)
Solutions
- Check the previous exception ($e->getPrevious()) — it holds libxml errors or the scanner message and pinpoints the cause
- Ensure the file is really SpreadsheetML: it must start with an XML declaration and carry the office:spreadsheet namespace
- Pick the right reader via IOFactory::identify()/load() instead of instantiating Reader\Xml directly
- Run xmllint or load the raw string with simplexml yourself to see the exact parse error
Example fix
// before
$xmlReader = new \PhpOffice\PhpSpreadsheet\Reader\Xml();
$spreadsheet = $xmlReader->load('export.xls'); // Cannot load invalid XML file: export.xls
// after: let IOFactory pick the reader for the actual format
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load('export.xls'); Defensive patterns
Strategy: validation
Validate before calling
libxml_use_internal_errors(true);
$raw = file_get_contents($path);
$probe = simplexml_load_string($raw);
if ($probe === false) {
$first = libxml_get_errors()[0] ?? null;
throw new InvalidArgumentException('Malformed XML: ' . ($first ? $first->message : 'unknown'));
} Try / catch
try {
$spreadsheet = $reader->load($path);
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
$cause = $e->getPrevious(); // libxml or security-scanner detail
// report $cause?->getMessage() to pinpoint the XML problem
} Prevention
- Use IOFactory::identify() instead of hardcoding Reader\Xml
- Inspect getPrevious() — it carries the real libxml/scanner error
- Reject uploads that fail a cheap simplexml well-formedness probe
When it happens
Trigger: Calling load()/loadIntoExisting() on a file that is not XML at all (binary .xls, zipped .xlsx, HTML), XML with encoding/name errors, or content the Xml reader's security scanner flags (e.g. DTD/XXE patterns); passing an empty filename yields the sibling 'Cannot load empty path' message.
Common situations: Using the Excel-2003-XML reader on wrong file types; user uploads renamed to .xml; files with BOM/encoding mismatches; strict security-scanner configuration.
Related errors
- ${filename} is an Invalid Spreadsheet file.
- Problem reading ${filename}
- $filename is an Invalid Spreadsheet file.
- Problem reading {$filename}
- Unsupported binary comparison operator
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/5f145e0cdb5ee047.
Report an issue: GitHub.