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

  1. Confirm the input is really SpreadsheetML and well-formed: run xmllint --noout file.xml or simplexml_load_string() on it before loading
  2. Let PhpSpreadsheet choose the reader: IOFactory::identify()/IOFactory::load() instead of instantiating Reader\Xml directly
  3. If loading from a string, validate with simplexml_load_string() first and handle false before calling the reader
  4. 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

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


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/a1f55be4650d6015. Report an issue: GitHub.