{"record":{"id":"a3ca26a2ec082cbc","repo":"Leantime/leantime","slug":"notification-plugin-zip-cant-open","errorCode":null,"errorMessage":"notification.plugin_zip_cant_open","messagePattern":"notification\\.plugin_zip_cant_open","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"app/Domain/Plugins/Services/Plugins.php","lineNumber":741,"sourceCode":"            && ! File::deleteDirectory($pluginDir)\n        ) {\n            throw new \\Exception(__('notification.plugin_cant_remove'));\n        }\n\n        if (! mkdir($pluginDir) && ! is_dir($pluginDir)) {\n            throw new \\RuntimeException(sprintf('Directory \"%s\" was not created', $pluginDir));\n        }\n\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)) {","sourceCodeStart":723,"sourceCodeEnd":759,"githubUrl":"https://github.com/Leantime/leantime/blob/9a9f49f1008f4782b30f6723c54228f4f992e636/app/Domain/Plugins/Services/Plugins.php#L723-L759","documentation":"The match maps ZipArchive::ER_OPEN to \"Zip: Can't open file\". Distinct from ER_NOENT (file absent): here the path exists but the OS refused to open it - a permission or policy problem on the temp file itself, since libzip opens it read/write for verification.","triggerScenarios":"installMarketplacePlugin() where the temp zip was written but cannot be opened: restrictive umask making the file unreadable to the effective user in edge setups, SELinux/AppArmor denying open on /tmp files, a read-only filesystem mount for /tmp, or file attributes (immutable) set on a leftover archive.","commonSituations":"SELinux targeted policy blocking httpd from reading user-created /tmp files; hardened /tmp mounts (ro); leftover temp file with immutable attribute from a previous attempt.","solutions":["ls -l /tmp/{Folder}.zip and confirm the web server user can read AND write it (libzip reopens the archive).","Check audit logs for SELinux denials: ausearch -m avc -ts recent; restore context or adjust policy.","Ensure /tmp is mounted read-write (mount | grep tmp).","Remove any stale archive (rm -f) so a fresh, properly-owned file is written, then retry."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (! is_readable($temporaryFile)) {\n    throw new RuntimeException(\"Temp archive {$temporaryFile} exists but is not readable - permissions/SELinux\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure the web user can read files it just wrote into the temp dir (sane umask).","On SELinux hosts, allow the web context read access to /tmp files.","Mount /tmp read-write."],"tags":["plugins","ziparchive","permissions","selinux"],"backgroundTag":"file-open-permission-denied","analyzedSha":"9a9f49f1008f4782b30f6723c54228f4f992e636","analyzedAt":"2026-08-21T02:37:38.966Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}