{"record":{"id":"94d92d157fa31268","repo":"Leantime/leantime","slug":"notification-cant-add-to-db","errorCode":null,"errorMessage":"notification_cant_add_to_db","messagePattern":"notification_cant_add_to_db","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"app/Domain/Plugins/Services/Plugins.php","lineNumber":760,"sourceCode":"            \\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.\n     * @return bool Returns true if the license is valid or the plugin is not of the marketplace type; returns false otherwise.\n     */\n    public function validLicense(InstalledPlugin $plugin): bool\n    {\n\n        if ($plugin->getType() !== $this->pluginTypes['marketplace']) {\n            return true;\n        }\n\n        $numberOfUsers = $this->usersService->getNumberOfUsers(activeOnly: true, includeApi: false);\n        $instanceId = $this->settingsService->getCompanyId();","sourceCodeStart":742,"sourceCodeEnd":778,"githubUrl":"https://github.com/Leantime/leantime/blob/9a9f49f1008f4782b30f6723c54228f4f992e636/app/Domain/Plugins/Services/Plugins.php#L742-L778","documentation":"The final step of installMarketplacePlugin(): files are extracted and registered via pluginRepository->addPlugin($pluginModel); when the insert returns falsy it throws __('notification_cant_add_to_db'). The repository returns false instead of throwing on a failed INSERT, so this is a silent database failure - constraint violation, duplicate row, dropped connection, or missing table after a skipped migration. Note the plugin files are already on disk at this point, leaving an unregistered (orphaned) folder.","triggerScenarios":"addPlugin() INSERT into zp_plugins failing: a row for the same plugin folder/name already exists (leftover from a failed prior update), the DB user lacks INSERT privileges, the connection dropped during the long download/extract window, or the zp_plugins schema is out of date because system updates were skipped.","commonSituations":"Re-installing a plugin whose DB record survived an earlier failed update (files deleted, row kept - the inverse also happens); partial Leantime version upgrades; restricted DB grants on managed hosting; long-running install hitting wait_timeout.","solutions":["Inspect zp_plugins for an existing row matching the plugin's foldername/name - remove or update it, then retry.","Check storage/logs/laravel.log for the underlying query error around the failure time.","Confirm the schema is current: run the update (php bin/leantime system:update or the update prompt).","Verify DB grants for INSERT on zp_plugins.","Clean up the orphaned extracted folder if you abandon the install, so a retry does not hit the removal path instead."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// idempotent install: drop any DB row + folder left by a previous failed run\nif ($existing = $pluginRepository->getPluginByFolder($foldername)) {\n    $pluginRepository->removePlugin($existing->id);\n}\nif (is_dir($pluginDir)) {\n    File::deleteDirectory($pluginDir);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $plugins->installMarketplacePlugin($plugin, $version);\n} catch (\\Exception $e) {\n    if ($e->getMessage() === __('notification_cant_add_to_db')) {\n        // files are on disk but unregistered: surface the state for manual repair\n        Log::error('Plugin files extracted but DB insert failed for '.$plugin->identifier);\n        return back()->with('error', 'Plugin registered in filesystem only - check DB logs and retry.');\n    }\n    throw $e;\n}","preventionTips":["Check zp_plugins for an existing row before reinstalling a plugin.","Keep the Leantime DB schema current (system:update) before installs.","Watch storage/logs/laravel.log for silent insert failures during installs.","Clean up orphaned plugin folders after failed installs."],"tags":["plugins","database","installation"],"backgroundTag":"database-insert-failed","analyzedSha":"9a9f49f1008f4782b30f6723c54228f4f992e636","analyzedAt":"2026-08-21T02:37:38.966Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}