{"record":{"id":"f46c8c49b179679c","repo":"SonarSource/sonarqube","slug":"no-plugin-with-key-s-or-plugin-s-is-already","errorCode":null,"errorMessage":"No plugin with key '%s' or plugin '%s' is already installed in latest version","messagePattern":"No plugin with key '(.+?)' or plugin '(.+?)' is already installed in latest version","errorType":"http","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/plugins/ws/InstallAction.java","lineNumber":124,"sourceCode":"    Optional<String> pluginRiskConsent = configuration.get(PLUGINS_RISK_CONSENT);\n    return pluginRiskConsent.filter(s -> PluginRiskConsent.valueOf(s) == PluginRiskConsent.ACCEPTED).isPresent();\n  }\n\n  private PluginUpdate findAvailablePluginByKey(String key) {\n    PluginUpdate pluginUpdate = null;\n\n    Optional<UpdateCenter> updateCenter = updateCenterFactory.getUpdateCenter(false);\n    if (updateCenter.isPresent()) {\n      pluginUpdate = updateCenter.get().findAvailablePlugins()\n        .stream()\n        .filter(Objects::nonNull)\n        .filter(u -> key.equals(u.getPlugin().getKey()))\n        .findFirst()\n        .orElse(null);\n    }\n\n    if (pluginUpdate == null) {\n      throw new IllegalArgumentException(\n        format(\"No plugin with key '%s' or plugin '%s' is already installed in latest version\", key, key));\n    }\n    if (isEditionBundled(pluginUpdate.getPlugin())) {\n      throw new IllegalArgumentException(format(\n        \"SonarSource commercial plugin with key '%s' can only be installed as part of a SonarSource edition\",\n        pluginUpdate.getPlugin().getKey()));\n    }\n\n    return pluginUpdate;\n  }\n}\n","sourceCodeStart":106,"sourceCodeEnd":136,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/plugins/ws/InstallAction.java#L106-L136","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Make installation idempotent: query api/plugins/installed first and only call install when a newer version is offered.","Ensure sonar.updatecenter.url is reachable (proxy/firewall) so the update center list is populated; then retry."],"exampleFix":"// before\nawait api.plugins.install({ key: 'sonar-python' }); // fails when already latest\n// after\nconst available = await api.plugins.available();\nif (available.plugins.some(p => p.key === 'sonar-python')) {\n  await api.plugins.install({ key: 'sonar-python' });\n}","handlingStrategy":"validation","validationCode":"const available = (await api.plugins.available()).plugins;\nconst installed = (await api.plugins.installed()).plugins;\nconst canInstall = available.some(p => p.key === key) && !atLatestVersion(installed, key);\nif (!canInstall) throw new Error(`nothing to install for key '${key}'`);","typeGuard":"function canInstall(available, installed, key) {\n  return available.some(p => p.key === key) &&\n    !(installed.some(p => p.key === key) && updateCenterHasNoNewer(key));\n}","tryCatchPattern":"try {\n  await api.plugins.install({ key });\n} catch (e) {\n  if (String(e.message).startsWith('No plugin with key')) {\n    log(`skipping '${key}': unknown or already at latest version`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Make install scripts idempotent by checking installed/available state first.","Verify exact plugin keys from the marketplace API, not plugin names.","Ensure the update center is reachable so the available list is populated."],"tags":["sonarqube","webapi","plugin","update-center"],"backgroundTag":"resource-not-found","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}