PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception

Unable to identify a reader for this file

Error message

Unable to identify a reader for this file

What it means

IOFactory::load()/identify() first guesses a reader from the file extension, then falls back to trying canRead() on every registered reader. If the guessed reader rejects the file and so does every other one, this exception is thrown: the file is not recognizable as any supported spreadsheet format. It is a content-signature failure, not a permissions error.

Source

Thrown at src/PhpSpreadsheet/IOFactory.php:218

            // Let's see if we are lucky
            if ($reader->canRead($filename)) {
                return $reader;
            }
        }

        // If we reach here then "lucky guess" didn't give any result
        // Try walking through all the options in self::$readers (or the selected subset)
        foreach ($testReaders as $readerType => $class) {
            //    Ignore our original guess, we know that won't work
            if ($readerType !== $guessedReader) {
                $reader = self::createReader($readerType, $testReaders);
                if ($reader->canRead($filename)) {
                    return $reader;
                }
            }
        }

        throw new Reader\Exception('Unable to identify a reader for this file');
    }

    /**
     * Guess a reader type from the file extension, if any.
     */
    private static function getReaderTypeFromExtension(string $filename): ?string
    {
        $pathinfo = pathinfo($filename);
        if (!isset($pathinfo['extension'])) {
            return null;
        }

        return match (strtolower($pathinfo['extension'])) {
            // Excel (OfficeOpenXML) Spreadsheet
            'xlsx',
            // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
            'xlsm',
            // Excel (OfficeOpenXML) Template

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Open with the concrete reader you expect (e.g. new Reader\Xlsx()) to get a clearer error
  2. Verify the file signature first: ZIP 'PK' header for .xlsx, OLE header for .xls
  3. Reject password-protected workbooks early with a clear user-facing message
  4. Validate uploads by content type, not just extension

Example fix

// before
$spreadsheet = IOFactory::load($uploadedPath);

// after
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
if (!$reader->canRead($uploadedPath)) {
    throw new InvalidArgumentException('Not a readable XLSX file');
}
$spreadsheet = $reader->load($uploadedPath);
Defensive patterns

Strategy: validation

Validate before calling

/** Cheap signature check before IOFactory::load(). */
function looksLikeSpreadsheet(string $path): bool
{
    $fh = fopen($path, 'rb');
    if ($fh === false) {
        return false;
    }
    $head = (string) fread($fh, 8);
    fclose($fh);

    return str_starts_with($head, 'PK')        // zip: xlsx/ods
            || str_starts_with($head, "\xd0\xcf\x11\xe0") // OLE: legacy xls
            || trim($head) === ''                 // possible csv/sylk
            || stripos($head, '<') !== false;     // html/xml-ish
}

if (!looksLikeSpreadsheet($uploadedPath)) {
    throw new InvalidArgumentException('Uploaded file is not a spreadsheet');
}
$spreadsheet = IOFactory::load($uploadedPath);

Try / catch

try {
    $spreadsheet = IOFactory::load($uploadedPath);
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
    if (str_contains($e->getMessage(), 'Unable to identify a reader')) {
        // user-facing error: the file is not a supported spreadsheet (or is encrypted)
        throw new UploadRejectException('Unsupported or corrupted file. Please upload XLSX, XLS, ODS or CSV.', 0, $e);
    }
    throw $e;
}

Prevention

When it happens

Trigger: IOFactory::load('report.xyz') with an unrecognized format; a password-protected/encrypted .xlsx (canRead fails); an HTML error page or empty file named .xlsx; a truncated upload.

Common situations: User uploads with spoofed or missing extensions; encrypted workbooks (PhpSpreadsheet cannot decrypt); API responses saved as .xlsx that are actually JSON/HTML; CSVs with unusual encodings failing the Csv canRead heuristic.

Related errors


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