Leantime/leantime · error · Exception
notification_cant_add_to_db
Error message
notification_cant_add_to_db
What it means
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.
Source
Thrown at app/Domain/Plugins/Services/Plugins.php:760
\ZipArchive::ER_READ => throw new \Exception(__('notification.plugin_zip_read_err')),
\ZipArchive::ER_SEEK => throw new \Exception(__('notification.plugin_zip_seek_err')),
default => throw new \Exception(__('notification.plugin_zip_unknown_err')),
true => null,
};
if (! $zip->extractTo($pluginDir)) {
throw new \Exception(__('notification.plugin_zip_cant_extract'));
}
$zip->close();
unlink($temporaryFile);
// read the composer.json content from the plugin phar file
$pluginModel = $this->createPluginFromComposer($foldername, $plugin->license);
if (! $this->pluginRepository->addPlugin($pluginModel)) {
throw new \Exception(__('notification_cant_add_to_db'));
}
}
/**
* Validates the license of a given plugin.
*
* @param InstalledPlugin $plugin The plugin object for which the license validity is being checked.
* @return bool Returns true if the license is valid or the plugin is not of the marketplace type; returns false otherwise.
*/
public function validLicense(InstalledPlugin $plugin): bool
{
if ($plugin->getType() !== $this->pluginTypes['marketplace']) {
return true;
}
$numberOfUsers = $this->usersService->getNumberOfUsers(activeOnly: true, includeApi: false);
$instanceId = $this->settingsService->getCompanyId();View on GitHub (pinned to 9a9f49f100)
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.
Defensive patterns
Strategy: try-catch
Validate before calling
// idempotent install: drop any DB row + folder left by a previous failed run
if ($existing = $pluginRepository->getPluginByFolder($foldername)) {
$pluginRepository->removePlugin($existing->id);
}
if (is_dir($pluginDir)) {
File::deleteDirectory($pluginDir);
} Try / catch
try {
$plugins->installMarketplacePlugin($plugin, $version);
} catch (\Exception $e) {
if ($e->getMessage() === __('notification_cant_add_to_db')) {
// files are on disk but unregistered: surface the state for manual repair
Log::error('Plugin files extracted but DB insert failed for '.$plugin->identifier);
return back()->with('error', 'Plugin registered in filesystem only - check DB logs and retry.');
}
throw $e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- notifications.plugin_install_cant_find_composer
- notification.plugin_cant_download
- notification.plugin_cant_remove
- Directory "%s" was not created
- notification.plugin_zip_exists
AI-assisted analysis of Leantime/leantime@9a9f49f100 (2026-08-21).
Data as JSON: /api/errors/94d92d157fa31268.
Report an issue: GitHub.