getgrav/grav · error · RuntimeException
ZipArchiver: failed to read entry "{name}" from {archive_fil
Error message
ZipArchiver: failed to read entry "{name}" from {archive_file}. What it means
When the size cap is active, ZipArchiver extracts through extractStreamed(), reading each entry with $zip->getStream($name). If getStream returns false for an entry, the archiver calls abortExtraction(): it closes the zip, deletes the partially-extracted destination folder (so nothing half-written remains), and throws RuntimeException 'ZipArchiver: failed to read entry "<name>" from <archive>'. A single unreadable entry aborts and rolls back the whole extraction.
Source
Thrown at system/src/Grav/Common/Filesystem/ZipArchiver.php:261
fclose($stream);
}
}
/**
* Close the archive, remove everything extracted so far, and throw. Keeps a
* rejected archive from leaving partial output on disk.
*
* @param ZipArchive $zip
* @param string $destination
* @param string $message
* @return never
*/
protected function abortExtraction(ZipArchive $zip, string $destination, string $message): void
{
$zip->close();
Folder::delete($destination);
throw new RuntimeException($message);
}
/**
* @param string $source
* @param callable|null $status
* @return $this
*/
public function compress($source, ?callable $status = null)
{
if (!extension_loaded('zip')) {
throw new InvalidArgumentException('ZipArchiver: Zip PHP module not installed...');
}
// Get real path for our folder
$rootPath = realpath($source);
if (!$rootPath) {
throw new InvalidArgumentException('ZipArchiver: ' . $source . ' cannot be found...');
}View on GitHub (pinned to 6040efed04)
Solutions
- Test the archive: unzip -t file.zip pinpoints bad entries; re-download or re-create the archive if any fail
- If the zip is password-protected, decrypt/re-pack it without a password before feeding it to ZipArchiver (it has no password support)
- Check for concurrent modification — do not rebuild the zip while extraction runs
- Update the zip extension/libzip on legacy systems to fix per-entry zip64 read failures
Defensive patterns
Strategy: try-catch
Validate before calling
$zip = new ZipArchive();
if ($zip->open($path) === true) {
for ($i = 0; $i < $zip->count(); $i++) {
$stat = $zip->statIndex($i);
if (($stat['encryption_method'] ?? 0) !== 0) {
$zip->close();
throw new RuntimeException('Encrypted entries are not supported: ' . $stat['name']);
}
}
$zip->close();
} Try / catch
try {
(new ZipArchiver($path))->extract($destination);
} catch (RuntimeException $e) {
if (str_contains($e->getMessage(), 'failed to read entry')) {
// destination was auto-rolled back; unzip -t to find the bad entry, re-download/re-pack, retry
}
} Prevention
- Run unzip -t on incoming archives — per-entry corruption shows up there first
- Do not feed password-protected zips into this path; it has no password support
- Note that failure here is all-or-nothing: the destination folder is deleted on abort, so retry from a clean state
When it happens
Trigger: A corrupt or mismatched central directory (entry declared but data unreadable); password-encrypted entries — getStream() fails for encrypted zips; CRC errors or truncated entry data from an incomplete download; archive modified while being extracted.
Common situations: Partially downloaded GPM packages; password-protected zips uploaded where the workflow expects plain ones; storage-level corruption on uploads; archives created by tools with zip64 quirks that older libzip mishandles per-entry.
Related errors
- ZipArchiver: Failed to open {archive_file}
- ZipArchiver: refused to extract {archive_file}. Archive exce
- ZipArchiver: refused to extract {archive_file}. Entry "{name
- ZipArchiver: refused to extract {archive_file}. Entry "{name
- ZipArchiver: refused to extract {archive_file}. Archive exce
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/828969d21200a97f.
Report an issue: GitHub.