{"record":{"id":"9f42c844f325e7af","repo":"Leantime/leantime","slug":"notification-plugin-zip-no-file","errorCode":null,"errorMessage":"notification.plugin_zip_no_file","messagePattern":"notification\\.plugin_zip_no_file","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"app/Domain/Plugins/Services/Plugins.php","lineNumber":739,"sourceCode":"        if (\n            is_dir($pluginDir = \"{$this->pluginDirectory}{$foldername}\")\n            && ! 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);","sourceCodeStart":721,"sourceCodeEnd":757,"githubUrl":"https://github.com/Leantime/leantime/blob/9a9f49f1008f4782b30f6723c54228f4f992e636/app/Domain/Plugins/Services/Plugins.php#L721-L757","documentation":"The match maps ZipArchive::ER_NOENT to 'Zip: No such file'. open() was handed a path to a temp file that no longer exists. In this flow file_put_contents() succeeded moments earlier (Plugins.php:712-719), so between the write and the open the file vanished or the constructed path is wrong.","triggerScenarios":"installMarketplacePlugin() where /tmp/{Folder}.zip is deleted between write and open: aggressive tmp cleaners (systemd-tmpfiles, docker sidecar janitors, hosting cron jobs purging /tmp), a filename parsed from Content-Disposition that resolves differently than expected, or open_basedir affecting path resolution.","commonSituations":"Hardened images running periodic /tmp cleanup with short retention; shared hosts purging /tmp every few minutes; concurrent installs racing on the same filename.","solutions":["Immediately after a failed install, check whether /tmp/{Folder}.zip exists to confirm the vanish vs a bad path.","Disable or slow down tmp-cleaning daemons/cron for the install window.","Point sys_temp_dir to a private directory no janitor touches and retry.","Log $temporaryFile right before open() to rule out Content-Disposition parsing producing a different name than expected."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// re-check between write and open\ndeclare(ticks = 0);\n$tempFile = Str::finish(sys_get_temp_dir(), '/').$filename;\nif (! is_file($tempFile) || filesize($tempFile) !== strlen($response->body())) {\n    throw new RuntimeException('Temp archive vanished or short after write - check tmp cleaners');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Disable aggressive /tmp janitors (systemd-tmpfiles, cron cleaners) or point sys_temp_dir to a private directory.","Avoid concurrent installs of the same plugin (they share the temp filename).","Log the temp path used so vanish-vs-bad-path is distinguishable."],"tags":["plugins","ziparchive","temp-dir","filesystem"],"backgroundTag":"temporary-file-missing","analyzedSha":"9a9f49f1008f4782b30f6723c54228f4f992e636","analyzedAt":"2026-08-21T02:37:38.966Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}