PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

File appears to be corrupt

Error message

File appears to be corrupt

What it means

getUInt2d() reads two bytes at a position confirmed against the data length; when the position is at/past the end of the loaded byte stream, confirmPos() throws 'File appears to be corrupt'. In practice the data ended earlier than the record structure promised.

Solutions

  1. Verify the transfer end-to-end: compare file size/checksum with the source and re-download
  2. Confirm the file opens in Excel; if Excel also complains, it is genuinely truncated
  3. Extract a fresh copy from the original archive or re-export from the source system
  4. Raise/verify upload_max_filesize and post_max_size and check for proxy limits if it came from HTTP upload
Defensive patterns

Strategy: validation

Validate before calling

if (!is_file($path) || filesize($path) === 0 || filesize($path) < 512) {
    throw new InvalidArgumentException('File missing, empty, or truncated: ' . $path);
}

Try / catch

try {
    $spreadsheet = IOFactory::load($path);
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
    if (str_contains($e->getMessage(), 'File appears to be corrupt')) {
        // likely truncated transfer: compare checksum with source and re-download
    }
}

Prevention

When it happens

Trigger: A truncated .xls (interrupted upload/download, disk-full during write, partial archive extraction) where the reader walks records past EOF; files whose OLE workbook stream was cut short.

Common situations: User uploads cut off by PHP upload limits or proxy timeouts; files copied from failing media; spreadsheets embedded in PDFs/documents extracted incompletely.

Related errors


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

Appendix: source

Thrown at src/PhpSpreadsheet/Reader/XlsBase.php:374

        for ($i = 0; $i < $strLen; ++$i) {
            $uncompressedString .= $string[$i] . "\0";
        }

        return $uncompressedString;
    }

    /**
     * Convert string to UTF-8. Only used for BIFF5.
     */
    protected function decodeCodepage(string $string): string
    {
        return StringHelper::convertEncoding($string, 'UTF-8', $this->codepage);
    }

    protected static function confirmPos(string $data, int $pos): void
    {
        if ($pos >= strlen($data)) {
            throw new PhpSpreadsheetException('File appears to be corrupt'); // @codeCoverageIgnore
        }
    }

    /**
     * Read 16-bit unsigned integer.
     */
    public static function getUInt2d(string $data, int $pos): int
    {
        self::confirmPos($data, $pos + 1);

        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8);
    }

    /**
     * Read 16-bit signed integer.
     */
    public static function getInt2d(string $data, int $pos): int
    {

View on GitHub (pinned to 65b080eef4)