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.

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)

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.