PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception
Cannot load invalid XML $fileOrString: $filename
Error message
Cannot load invalid XML $fileOrString: $filename
What it means
Thrown by the SpreadsheetML (Excel 2003 XML) reader when simplexml cannot parse the input; the message records whether the input was a file or a string ('Cannot load invalid XML file: ...' / '... string: ...', set in trySimpleXMLLoadStringPrivate at src/PhpSpreadsheet/Reader/Xml.php:122). It means the content is either not XML at all or violates XML well-formedness. For file input it only fires after File::assertFile() and the reader's canRead() signature check already passed; for string input no canRead check is performed, so any malformed string fails here.
Source
Thrown at src/PhpSpreadsheet/Reader/Xml.php:297
*
* @param string $filename file name if useContents is false else file contents
*/
public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet, bool $useContents = false): Spreadsheet
{
if ($useContents) {
$this->fileContents = $filename;
$fileOrString = 'string';
} else {
File::assertFile($filename);
if (!$this->canRead($filename)) {
throw new Exception($filename . ' is an Invalid Spreadsheet file.');
}
$fileOrString = 'file';
}
$xml = $this->trySimpleXMLLoadStringPrivate($filename, $fileOrString);
if ($xml === false) {
throw new Exception($this->xmlFailMessage);
}
$namespaces = $xml->getNamespaces(true);
(new Properties($spreadsheet))->readProperties($xml, $namespaces);
$this->styles = (new Style())->parseStyles($xml, $namespaces);
if (isset($this->styles['Default']) && is_array($this->styles['Default'])) {
$spreadsheet->getCellXfCollection()[0]->applyFromArray($this->styles['Default']);
}
$worksheetID = 0;
$xml_ss = $xml->children(self::NAMESPACES_SS);
$sheetCreated = false;
/** @var null|SimpleXMLElement $worksheetx */
foreach ($xml_ss->Worksheet as $worksheetx) {
$worksheet = $worksheetx ?? new SimpleXMLElement('<xml></xml>');View on GitHub (pinned to 65b080eef4)
Solutions
- Confirm the input is really SpreadsheetML and well-formed: run xmllint --noout file.xml or simplexml_load_string() on it before loading
- Let PhpSpreadsheet choose the reader: IOFactory::identify()/IOFactory::load() instead of instantiating Reader\Xml directly
- If loading from a string, validate with simplexml_load_string() first and handle false before calling the reader
- Re-export the source file as 'Excel 2003 XML' from Excel/LibreOffice to regenerate valid markup
Example fix
// before
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xml();
$spreadsheet = $reader->load('export.xml'); // throws on malformed markup
// after
$type = \PhpOffice\PhpSpreadsheet\IOFactory::identify('export.xml');
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile('export.xml')->load('export.xml'); Defensive patterns
Strategy: try-catch
Validate before calling
use PhpOffice\PhpSpreadsheet\Reader\Xml; $isReadable = (new Xml())->canRead($path); // cheap signature check $xmlOk = $isReadable && simplexml_load_string(file_get_contents($path)) !== false;
Type guard
function isParsableXml(string $content): bool
{
return simplexml_load_string($content) !== false;
} Try / catch
try {
$spreadsheet = $reader->load($path);
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
// covers both 'Cannot load invalid XML file: ...' and assertFile failures
logger()->warning('Rejected malformed spreadsheet', ['file' => $path, 'err' => $e->getMessage()]);
return null;
} Prevention
- Let IOFactory::identify() pick the reader instead of hardcoding Reader\Xml
- xmllint or simplexml-validate input from untrusted sources before loading
- Keep the reader's canRead() in upload validation flows
- For string loads, validate with simplexml_load_string() first
When it happens
Trigger: Calling Reader\Xml::loadSpreadsheetFromString() with a truncated or non-XML string (the string branch in loadSpreadsheetFromFile/FromString sets fileOrString='string' and skips canRead); loading a file that passes canRead() but contains unclosed tags or an invalid encoding declaration; passing an HTML error page fetched over HTTP as the spreadsheet string.
Common situations: Wrong reader forced for the actual format (an .xlsx renamed to .xml); truncated downloads; BOM-prefixed or entity-laden markup; strings built by concatenation that lose closing tags; CSV content fed to the XML reader.
Related errors
- Cannot load invalid XML ${fileOrString}: ${filename}
- Unable to identify a reader for this file
- Unsupported binary comparison operator
- Cloning the calculation engine is not allowed!
- Unsupported numeric binary operation
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/a1f55be4650d6015.
Report an issue: GitHub.