PCLZIP_ERR_BAD_FORMAT: The File Is Not the ZIP WordPress Expected
The error names PclZip, but PclZip is only the last of two unzippers to give up. By the time you read it, ZipArchive has already rejected the file too — so the archive is truncated or not a ZIP at all, and the fix is to find out what was actually downloaded.
PCLZIP_ERR_BAD_FORMAT means the file WordPress tried to unpack is not a complete ZIP archive. The full line usually reads The package could not be installed. PCLZIP_ERR_BAD_FORMAT (-10) : Unable to find End of Central Dir Record signature, and it appears after "Unpacking the update…" or "Unpacking the package…" on a plugin, theme or core update. The download finished; what arrived was not what WordPress expected.
Why the error names PclZip
unzip_file() uses PHP's ZipArchive first, whenever the class exists and the unzip_file_use_ziparchive filter allows it. Only if ZipArchive fails to open the file with an incompatible_archive error does WordPress fall through to its bundled PclZip library and try again. When PclZip also fails, its error is the one passed up, formatted by errorInfo( true ) as the error name, the code in brackets and PclZip's own description.
So the PclZip label is a red herring. The common reading — "the server lacks the zip extension, install it" — is backwards: on a server with ZipArchive loaded, PclZip only runs after ZipArchive has already refused the file. Two independent unzippers rejecting it is strong evidence the file itself is broken.
The descriptions you will see are all format failures in the archive's structure:
| PclZip description | Meaning |
|---|---|
Unable to find End of Central Dir Record signature |
The archive's index was not found — truncated, or not a ZIP |
Invalid End of Central Dir Record size |
The index was cut off partway |
Invalid archive structure |
Entries do not match the index — corrupted in transit |
Find out what was downloaded
WordPress deletes the package once unpacking fails, so reproduce the download by hand from the server. For a WordPress.org plugin:
curl -sL -o /tmp/test.zip https://downloads.wordpress.org/plugin/plugin-slug.zip
file /tmp/test.zip
unzip -t /tmp/test.zip | tail -1
Zip archive data and No errors detected mean the source is fine and the problem is on the path between it and WordPress. HTML document or JSON data means you downloaded an error page with a .zip name — open it, and the reason is usually written in plain text.
For a premium plugin you will not have a direct URL. Run the update with WP_DEBUG_LOG on and the plugin's own debug option if it has one, or ask the vendor for the download link their updater uses.
Causes, most common first
The vendor sent an error page with a 200 status. WordPress treats any non-200 response as a failed download, so a vendor that returns its "licence expired" page with status 200 gets past Download failed and fails here instead. Licences tied to the old domain after a migration are the classic trigger. Re-activate the licence for the current URL.
The download was truncated. A proxy, a security appliance or a flaky connection ended the transfer early with a valid status. The file has the right name and part of the content, and the index at the end is missing. Retrying often works; failing at the same size every time points to a proxy or a response size limit.
The temp partition filled up. The package is streamed to WordPress's temp folder (see WP_TEMP_DIR). A full disk truncates it silently. Check with df -h on the temp directory and on the partition holding wp-content.
You uploaded the wrong kind of file. Marketplaces often deliver a "full package" ZIP containing documentation, licences and the installable plugin ZIP inside it. That outer file is a valid archive and fails differently — with the no valid plugins message — but a file renamed to .zip, a .rar, or a macOS archive re-saved by a browser extension fails with BAD_FORMAT. Uploads through Plugins › Add New are checked with wp_zip_file_is_valid() before anything else and fail with a bare "Incompatible Archive."; seeing the PclZip name usually means the file came from an update, not an upload.
The upload was cut short. WordPress deletes a rejected upload, so copy the same file to the server over SFTP and compare checksums with the original:
sha256sum plugin.zip # run on both machines; the hashes must match
If the SFTP copy matches and unpacks cleanly but the browser upload fails, the browser path is truncating it — the limits involved are covered under upload_max_filesize.
Installing around it
When the source file is good but WordPress's copy keeps breaking, install by hand:
cd wp-content/plugins
unzip -q /tmp/test.zip
wp plugin activate plugin-slug
If the old version is in the way, move it aside first rather than deleting it, so you can roll back. This does not fix a truncating proxy or a full disk; the next update hits the same wall.
Common mistakes
- Installing
php-zipbecause the error mentions PclZip, whenZipArchivewas already present and also rejected the file. - Re-zipping the plugin folder on a Mac and uploading that: the archive is valid, but often has the wrong top-level structure.
- Forcing PclZip with
add_filter( 'unzip_file_use_ziparchive', '__return_false' ). It changes which library reports the error, not whether the file is complete. - Retrying an update twenty times against a vendor whose licence server returns an error page.
Verify
filereportsZip archive dataandunzip -treports no errors for the package from the server.- The update or install completes and the plugin list shows the expected version.
- The next unrelated update also succeeds, ruling out a disk or proxy problem.
wp-content/upgrade/is empty afterwards except forindex.php.
Frequently asked
- No. WordPress tries ZipArchive first whenever the extension is loaded and falls back to PclZip only when ZipArchive cannot open the file. Seeing a PclZip error therefore usually means both unzippers rejected the same file. The archive is the problem, not the extension.
- Because WordPress may not be opening that file. An update downloads its own copy from the vendor, and that copy can be an HTML error page or a truncated transfer. If you uploaded the file yourself, compare its size on the server with the original; an upload cut short by a proxy or a full disk is a different file from the one on your desktop.
- A ZIP's index sits at the very end of the file. PclZip looked for that index and did not find it, which happens when the file was cut off before the end or was never a ZIP to begin with — an HTML page, a JSON error or an empty response saved with a .zip name.