PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Reader\Exception
Decryption password incorrect
Error message
Decryption password incorrect
What it means
The RC4 password-verification step (document-id + salt + hashed-salt check ported from Spreadsheet-ParseExcel) failed for the configured password. PhpSpreadsheet defaults to 'VelvetSweatshop', the password Excel itself uses when a file is flagged encrypted without a user-supplied password; a file with a real password rejects that default.
Source
Thrown at src/PhpSpreadsheet/Reader/Xls.php:880
*/
protected function readFilepass(): void
{
$length = self::getUInt2d($this->data, $this->pos + 2);
if ($length < 54) {
throw new Exception('Unexpected file pass record length');
}
$recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
// move stream pointer to next record
$this->pos += 4 + $length;
if (substr($recordData, 0, 2) !== "\x01\x00" || substr($recordData, 4, 2) !== "\x01\x00") {
throw new Exception('Unsupported encryption algorithm');
}
if (!$this->verifyPassword($this->encryptionPassword, substr($recordData, 6, 16), substr($recordData, 22, 16), substr($recordData, 38, 16), $this->md5Ctxt)) {
throw new Exception('Decryption password incorrect');
}
$this->encryption = self::MS_BIFF_CRYPTO_RC4;
// Decryption required from the record after next onwards
$this->encryptionStartPos = $this->pos + self::getUInt2d($this->data, $this->pos + 2);
}
/**
* Make an RC4 decryptor for the given block.
*
* @param int $block Block for which to create decrypto
* @param string $valContext MD5 context state
*/
private function makeKey(int $block, string $valContext): Xls\RC4
{
$pwarray = str_repeat("\0", 64);
View on GitHub (pinned to 65b080eef4)
Solutions
- Call setEncryptionPassword('the-real-password') on the Xls reader instance before load()
- Trim the password string and confirm it in Excel (open + 'File > Info > Protect Workbook') to rule out typos
- If the file opens in Excel without prompting, let the 'VelvetSweatshop' default apply — but if it still throws, the salt bytes are damaged: re-save the file from Excel
Example fix
// before
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$spreadsheet = $reader->load('protected.xls'); // Decryption password incorrect
// after
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setEncryptionPassword(trim($userSuppliedPassword));
$spreadsheet = $reader->load('protected.xls'); Defensive patterns
Strategy: validation
Validate before calling
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
if ($knownPassword !== null && $knownPassword !== '') {
$reader->setEncryptionPassword(trim($knownPassword));
}
$spreadsheet = $reader->load($path); Try / catch
try {
$spreadsheet = $reader->load($path);
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
if (str_contains($e->getMessage(), 'Decryption password incorrect')) {
// re-prompt the user for the password and retry once
}
} Prevention
- Collect the password from the user/config before load, not after the failure
- Trim passwords and reject empty strings so the VelvetSweatshop default is a deliberate choice
- Store per-file passwords keyed by upload, not a single global one
When it happens
Trigger: Calling load() on a password-protected .xls without first calling setEncryptionPassword(), or passing a wrong/typo'd password; also a corrupt salt can make even the correct password fail verification.
Common situations: Uploading password-protected workbooks from users while the import pipeline assumes no password; password changed by the file owner; copy-paste of the password with trailing whitespace.
Related errors
- Unsupported encryption algorithm
- Unexpected file pass record length
- unable to unpack data
- XOr encryption not supported
- Unrecognized space type in tAttrSpace token
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/0bcf3f07271ded71.
Report an issue: GitHub.