PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception
Unable to read data from {$pFilename}
Error message
Unable to read data from {$pFilename} What it means
The Ods reader opens the file as a ZipArchive and parses its meta.xml entry with simplexml. When that entry is missing, empty, or unparseable, it throws 'Unable to read data from {$pFilename}'. Upstream bug worth knowing: the message is single-quoted, so it literally prints {$pFilename} and never shows the actual filename (the code variable is even named $filename).
Source
Thrown at src/PhpSpreadsheet/Reader/Ods.php:325
/**
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
*/
public function loadIntoExisting(string $filename, Spreadsheet $spreadsheet): Spreadsheet
{
File::assertFile($filename, self::INITIAL_FILE);
$zip = new ZipArchive();
$zip->open($filename);
// Meta
$xml = @simplexml_load_string(
$this->getSecurityScannerOrThrow()
->scan($zip->getFromName('meta.xml'))
);
if ($xml === false) {
throw new Exception('Unable to read data from {$pFilename}');
}
/** @var array{meta?: string, office?: string, dc?: string} */
$namespacesMeta = $xml->getNamespaces(true);
(new DocumentProperties($spreadsheet))->load($xml, $namespacesMeta);
// Styles
$this->allStyles = $this->numberFormats = [];
$dom = new DOMDocument('1.01', 'UTF-8');
$dom->loadXML(
$this->getSecurityScannerOrThrow()
->scan($zip->getFromName('styles.xml'))
);
$officeNs = (string) $dom->lookupNamespaceUri('office');
$styleNs = (string) $dom->lookupNamespaceUri('style');
$fontNs = (string) $dom->lookupNamespaceUri('fo');View on GitHub (pinned to 65b080eef4)
Solutions
- Re-save the file in LibreOffice or Excel so a complete, valid ODS (including meta.xml) is regenerated
- Verify the archive contents (unzip -l file.ods should list meta.xml); if absent, rebuild the zip with a minimal meta.xml or re-export
- Use IOFactory::identify() to confirm the file really is an ODS before blaming the reader
Example fix
# before (shell): file is an ODS lacking meta.xml
$spreadsheet = (new Ods())->load('report.ods'); // throws literal 'Unable to read data from {$pFilename}'
# after: regenerate a complete archive first
soffice --headless --convert-to ods --outdir fixed report.ods
$spreadsheet = (new Ods())->load('fixed/report.ods'); Defensive patterns
Strategy: validation
Validate before calling
$zip = new ZipArchive();
if ($zip->open($filename) !== true || $zip->locateName('meta.xml') === false) {
throw new RuntimeException('ODS archive missing or lacks meta.xml: ' . $filename);
}
$zip->close();
$spreadsheet = (new Ods())->load($filename); Prevention
- Pre-flight unknown ODS files with a ZipArchive meta.xml check
- Re-save odd exports through LibreOffice to normalize archive structure
- Remember the exception text literally says {$pFilename} — the filename is absent, so log your own path context
When it happens
Trigger: An .ods whose zip lacks meta.xml (some third-party generators omit it); a corrupt or truncated archive; a non-ODS zip merely renamed .ods; interrupted downloads.
Common situations: Files produced by lightweight Java/Python ODS writers that skip meta.xml; uploads corrupted in transit; archives rebuilt by tools that dropped entries.
Related errors
- Could not find zip member $zipfile
- Unknown codepage: $codePage
- dggContainer is unexpectedly null
- dgContainer is unexpectedly null
- spgrContainer is unexpectedly null
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/27ae1b6448845327.
Report an issue: GitHub.