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

  1. Inspect zp_plugins for an existing row matching the plugin's foldername/name - remove or update it, then retry.
  2. Check storage/logs/laravel.log for the underlying query error around the failure time.
  3. Confirm the schema is current: run the update (php bin/leantime system:update or the update prompt).
  4. Verify DB grants for INSERT on zp_plugins.
  5. 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

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


AI-assisted analysis of Leantime/leantime@9a9f49f100 (2026-08-21). Data as JSON: /api/errors/94d92d157fa31268. Report an issue: GitHub.