PHPOffice/PhpSpreadsheet · error · ReaderException
Unable to get contents of $filename
Error message
Unable to get contents of $filename
What it means
When the Csv reader's input encoding is not UTF-8, convertNonUtf8() re-reads the entire file with file_get_contents() to re-encode it. This exception fires if that read returns false — an environmental failure (the file vanished or became unreadable between the earlier fopen and this read), which is why upstream marks it @codeCoverageIgnore.
Source
Thrown at src/PhpSpreadsheet/Reader/Csv.php:313
if ($encoding !== '') {
$this->inputEncoding = $encoding;
}
}
if ($this->inputEncoding === self::GUESS_ENCODING) {
$this->inputEncoding = self::guessEncoding($filename, $this->fallbackEncoding);
}
$this->openFile($filename);
if ($this->inputEncoding !== 'UTF-8') {
$this->convertNonUtf8($filename);
}
}
protected function convertNonUtf8(string $filename): void
{
fclose($this->fileHandle);
$entireFile = file_get_contents($filename);
if ($entireFile === false) {
throw new ReaderException("Unable to get contents of $filename"); // @codeCoverageIgnore
}
$fileHandle = fopen('php://memory', 'r+b');
if ($fileHandle === false) {
throw new ReaderException('Unable to open php://memory'); // @codeCoverageIgnore
}
$this->fileHandle = $fileHandle;
$data = StringHelper::convertEncoding($entireFile, 'UTF-8', $this->inputEncoding);
fwrite($this->fileHandle, $data);
$this->skipBOM();
}
public function setTestAutoDetect(bool $value): self
{
$this->testAutodetect = $value;
return $this;
}
View on GitHub (pinned to 65b080eef4)
Solutions
- Copy the upload to a temp file you control before loading, and load that copy
- Ensure nothing deletes or mutates the file while the reader runs (adjust tmp retention)
- Run 64-bit PHP for very large files
Example fix
// before
$spreadsheet = (new Csv())->load('/tmp/queue/incoming.csv'); // cleaner may unlink mid-load
// after
$stable = tempnam(sys_get_temp_dir(), 'csv');
copy($incomingPath, $stable);
$spreadsheet = (new Csv())->load($stable);
unlink($stable); Defensive patterns
Strategy: validation
Validate before calling
if (!is_readable($filename)) {
throw new RuntimeException("Input vanished or unreadable: $filename");
}
$stable = tempnam(sys_get_temp_dir(), 'csv');
copy($filename, $stable); // decouple from cleanup races
$spreadsheet = (new Csv())->load($stable);
unlink($stable); Prevention
- Parse a private copy of transient files (uploads, tmp) rather than the original path
- Keep tmp-retention longer than your max job runtime
- Run 64-bit PHP builds for very large file imports
When it happens
Trigger: The file is deleted or its permissions change mid-request (temp-dir cleanup race); a 2GB+ file on a 32-bit PHP build where size handling fails; filesystem faults while the import runs.
Common situations: Long-running queue jobs parsing uploads stored in an aggressively cleaned tmp directory; files larger than PHP's integer handling on 32-bit deployments.
Related errors
- Unable to open php://memory
- Code page $codePage not implemented on this system.
- Could not open file {filename} for reading.
- $filename is an Invalid Spreadsheet file.
- Could not open file $filename for reading.
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/1397c9b598c914d1.
Report an issue: GitHub.