{"record":{"id":"60930104429f9fe3","repo":"Leantime/leantime","slug":"notification-plugin-zip-cant-extract","errorCode":null,"errorMessage":"notification.plugin_zip_cant_extract","messagePattern":"notification\\.plugin_zip_cant_extract","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"app/Domain/Plugins/Services/Plugins.php","lineNumber":749,"sourceCode":"\n        $zip = new \\ZipArchive;\n\n        match ($zip->open($temporaryFile)) {\n            \\ZipArchive::ER_EXISTS => throw new \\Exception(__('notification.plugin_zip_exists')),\n            \\ZipArchive::ER_INCONS => throw new \\Exception(__('notification.plugin_zip_inconsistent')),\n            \\ZipArchive::ER_INVAL => throw new \\Exception(__('notification.plugin_zip_invalid_arg')),\n            \\ZipArchive::ER_MEMORY => throw new \\Exception(__('notification.plugin_zip_malloc')),\n            \\ZipArchive::ER_NOENT => throw new \\Exception(__('notification.plugin_zip_no_file')),\n            \\ZipArchive::ER_NOZIP => throw new \\Exception(__('notification.plugin_zip_not_zip')),\n            \\ZipArchive::ER_OPEN => throw new \\Exception(__('notification.plugin_zip_cant_open')),\n            \\ZipArchive::ER_READ => throw new \\Exception(__('notification.plugin_zip_read_err')),\n            \\ZipArchive::ER_SEEK => throw new \\Exception(__('notification.plugin_zip_seek_err')),\n            default => throw new \\Exception(__('notification.plugin_zip_unknown_err')),\n            true => null,\n        };\n\n        if (! $zip->extractTo($pluginDir)) {\n            throw new \\Exception(__('notification.plugin_zip_cant_extract'));\n        }\n\n        $zip->close();\n\n        unlink($temporaryFile);\n\n        // read the composer.json content from the plugin phar file\n        $pluginModel = $this->createPluginFromComposer($foldername, $plugin->license);\n\n        if (! $this->pluginRepository->addPlugin($pluginModel)) {\n            throw new \\Exception(__('notification_cant_add_to_db'));\n        }\n    }\n\n    /**\n     * Validates the license of a given plugin.\n     *\n     * @param  InstalledPlugin  $plugin  The plugin object for which the license validity is being checked.","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/Leantime/leantime/blob/9a9f49f1008f4782b30f6723c54228f4f992e636/app/Domain/Plugins/Services/Plugins.php#L731-L767","documentation":"After ZipArchive::open() succeeded, extractTo($pluginDir) returned false: 'Could not extract plugin'. The archive opened fine but one or more entries could not be written or decompressed - per-entry CRC failures, a compression method libzip cannot extract, insufficient permissions/space in the freshly created app/Plugins/{Folder}, or entries whose paths cannot be created.","triggerScenarios":"installMarketplacePlugin() where extraction into app/Plugins/{Folder} fails: the PHP user cannot write into the just-created directory (umask/ownership edge cases), the disk fills mid-extract (uncompressed size exceeds free space), the zip uses an unsupported compression (e.g. Deflate64/PPMd), or individual entries fail CRC.","commonSituations":"Disk space exhausted by the uncompressed plugin (asset-heavy plugins); marketplace artifacts produced with non-standard compression; permission surprises right after the mkdir; partial extraction leaving a broken half-plugin that then also trips error 82 on the next attempt.","solutions":["Verify free space covers the uncompressed size: df -h app/Plugins (zips typically expand 2-5x).","Confirm the PHP user can write into app/Plugins/{Folder}: touch a test file as that user.","Copy the temp zip and run unzip -t / unzip -d against it on the server to see the concrete entry-level error.","If unzip also fails, the artifact is bad - report that plugin/version to Leantime.","Clean the half-extracted folder before retrying so error 82 does not mask the original failure."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// preflight: space for the uncompressed payload and a writable destination\nif (disk_free_space($this->pluginDirectory) < $zipUncompressedBytes) {\n    throw new RuntimeException('Insufficient disk space to extract plugin');\n}\nif (! is_writable($this->pluginDirectory)) {\n    throw new RuntimeException('Plugin directory not writable - extraction will fail');\n}","typeGuard":null,"tryCatchPattern":"catch (\\Exception $e) {\n    if ($e->getMessage() === __('notification.plugin_zip_cant_extract')) {\n        // half-extracted dir must be removed or the next attempt fails elsewhere\n        File::deleteDirectory($pluginDir);\n        return back()->with('error', 'Extraction failed - check disk space and permissions, then retry.');\n    }\n    throw $e;\n}","preventionTips":["Reserve disk for the uncompressed size, not just the zip.","Verify artifacts with unzip -t when installs fail repeatedly.","Always clean the partially extracted folder after a failed extraction."],"tags":["plugins","ziparchive","extraction","disk-space"],"backgroundTag":"zip-extraction-failed","analyzedSha":"9a9f49f1008f4782b30f6723c54228f4f992e636","analyzedAt":"2026-08-21T02:37:38.966Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}