SonarSource/sonarqube · error · IllegalArgumentException

No plugin with key ' ' or plugin ' ' is already installed…

Error message

No plugin with key '%s' or plugin '%s' is already installed in latest version

What it means

After edition and consent checks, InstallAction resolves the requested key against available plugin updates from the update center (new plugins plus already-installed plugins whose latest version differs from the installed one). If no PluginUpdate matches the key, it throws IllegalArgumentException stating the plugin does not exist or is already at its latest version.

Solutions

  1. Check GET api/plugins/available to confirm the exact key exists and is not already installed in the latest version; skip the call if so.
  2. Make installation idempotent: query api/plugins/installed first and only call install when a newer version is offered.
  3. Ensure sonar.updatecenter.url is reachable (proxy/firewall) so the update center list is populated; then retry.

Example fix

// before
await api.plugins.install({ key: 'sonar-python' }); // fails when already latest
// after
const available = await api.plugins.available();
if (available.plugins.some(p => p.key === 'sonar-python')) {
  await api.plugins.install({ key: 'sonar-python' });
}
Defensive patterns

Strategy: validation

Validate before calling

const available = (await api.plugins.available()).plugins;
const installed = (await api.plugins.installed()).plugins;
const canInstall = available.some(p => p.key === key) && !atLatestVersion(installed, key);
if (!canInstall) throw new Error(`nothing to install for key '${key}'`);

Type guard

function canInstall(available, installed, key) {
  return available.some(p => p.key === key) &&
    !(installed.some(p => p.key === key) && updateCenterHasNoNewer(key));
}

Try / catch

try {
  await api.plugins.install({ key });
} catch (e) {
  if (String(e.message).startsWith('No plugin with key')) {
    log(`skipping '${key}': unknown or already at latest version`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: POST api/plugins/install?key=<key> where the key matches no update-center entry: unknown key, typo, plugin already installed at the newest compatible version, or update center not yet populated/synced.

Common situations: Scripts installing a plugin that is already up to date (idempotent re-runs); key mismatch between marketplace name and plugin key; update center blocked by a proxy so the available-plugin list is empty.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/f46c8c49b179679c. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/plugins/ws/InstallAction.java:124

    Optional<String> pluginRiskConsent = configuration.get(PLUGINS_RISK_CONSENT);
    return pluginRiskConsent.filter(s -> PluginRiskConsent.valueOf(s) == PluginRiskConsent.ACCEPTED).isPresent();
  }

  private PluginUpdate findAvailablePluginByKey(String key) {
    PluginUpdate pluginUpdate = null;

    Optional<UpdateCenter> updateCenter = updateCenterFactory.getUpdateCenter(false);
    if (updateCenter.isPresent()) {
      pluginUpdate = updateCenter.get().findAvailablePlugins()
        .stream()
        .filter(Objects::nonNull)
        .filter(u -> key.equals(u.getPlugin().getKey()))
        .findFirst()
        .orElse(null);
    }

    if (pluginUpdate == null) {
      throw new IllegalArgumentException(
        format("No plugin with key '%s' or plugin '%s' is already installed in latest version", key, key));
    }
    if (isEditionBundled(pluginUpdate.getPlugin())) {
      throw new IllegalArgumentException(format(
        "SonarSource commercial plugin with key '%s' can only be installed as part of a SonarSource edition",
        pluginUpdate.getPlugin().getKey()));
    }

    return pluginUpdate;
  }
}

View on GitHub (pinned to 184c821202)