elastic/elasticsearch · error · UserException
78
78
Error message
plugin [%s] not found; run 'elasticsearch-plugin list' to get list of installed plugins
What it means
Thrown by RemovePluginAction.checkCanRemove when neither the plugin directory nor (conditionally) the plugin config dir exists, and no `.removing-<id>` marker is present. Exit code is CONFIG (78). The message guides the user to run `list` to see installed plugins. A special branch prints a different message for plugins that have become modules.
Source
Thrown at distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/RemovePluginAction.java:146
/*
* If the plugin does not exist and the plugin config does not exist, fail to the user that the plugin is not found, unless there's
* a marker file left from a previously failed attempt in which case we proceed to clean up the marker file. Or, if the plugin does
* not exist, the plugin config does, and we are not purging, again fail to the user that the plugin is not found.
*/
if ((Files.exists(pluginDir) == false && Files.exists(pluginConfigDir) == false && Files.exists(removing) == false)
|| (Files.exists(pluginDir) == false && Files.exists(pluginConfigDir) && this.purge == false)) {
if (PLUGINS_CONVERTED_TO_MODULES.contains(pluginId)) {
terminal.errorPrintln(
"plugin [" + pluginId + "] is no longer a plugin but instead a module packaged with this distribution of Elasticsearch"
);
} else {
final String message = String.format(
Locale.ROOT,
"plugin [%s] not found; run 'elasticsearch-plugin list' to get list of installed plugins",
pluginId
);
throw new UserException(ExitCodes.CONFIG, message);
}
}
final Path pluginBinDir = env.binDir().resolve(pluginId);
if (Files.exists(pluginBinDir)) {
if (Files.isDirectory(pluginBinDir) == false) {
throw new UserException(ExitCodes.IO_ERROR, "bin dir for " + pluginId + " is not a directory");
}
}
}
private void removePlugin(InstallablePlugin plugin) throws IOException {
final String pluginId = plugin.getId();
final Path pluginDir = env.pluginsDir().resolve(pluginId);
final Path pluginConfigDir = env.configDir().resolve(pluginId);
final Path removing = env.pluginsDir().resolve(".removing-" + pluginId);
terminal.println("-> removing [" + pluginId + "]...");View on GitHub (pinned to db6a809a66)
Solutions
- Run `elasticsearch-plugin list` and copy the exact installed id.
- If the id is now a module, no removal is needed (the CLI prints a notice).
- If you manually deleted the plugin dir, also remove any stale `.removing-<id>` marker or use `--purge`.
Example fix
# before: bin/elasticsearch-plugin remove analisys-icu # typo # after: bin/elasticsearch-plugin list # confirm exact id bin/elasticsearch-plugin remove analysis-icu
Defensive patterns
Strategy: validation
Validate before calling
// Confirm the plugin is installed before removing.
Path pluginDir = env.pluginsDir().resolve(id);
if (!Files.exists(pluginDir) && !Files.exists(env.configDir().resolve(id))) {
throw new FileNotFoundException("plugin not installed: " + id);
} Try / catch
try {
removeAction.execute(plugins);
} catch (UserException e) {
if (e.exitCode == ExitCodes.CONFIG && e.getMessage().contains("not found")) {
System.err.println("Run `elasticsearch-plugin list` to see installed plugins.");
}
throw e;
} Prevention
- Always source removal ids from `elasticsearch-plugin list` output.
- In automation, diff installed vs requested before invoking remove.
- Handle migrated-to-module ids specially (no removal needed).
When it happens
Trigger: checkCanRemove resolves pluginDir and pluginConfigDir; if pluginDir is absent AND (pluginConfigDir absent OR purge==false), it formats the not-found message and throws UserException(CONFIG). The PLUGINS_CONVERTED_TO_MODULES branch bypasses the throw for known migrated ids.
Common situations: Typo in the plugin id on `remove`; plugin already removed manually; plugin never installed on this node; id is a legacy name now shipped as a module.
Related errors
- 78
- 64
- classname is a required setting for esplugin
- classname is a forbidden for stable esplugin
- invalid deploymentTarget '{}', expected one of {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/ac59928e60a05a91.
Report an issue: GitHub.