elastic/elasticsearch · error · PluginSyncException

Failed to list existing plugins

Error message

Failed to list existing plugins

What it means

Thrown when an IOException occurs while listing installed plugins via Files.newDirectoryStream(env.pluginsDir()) or reading a plugin's descriptor properties. The sync action wraps any I/O failure in PluginSyncException so the caller (SyncPluginsCliProvider) can surface it as a CONFIG error.

Source

Thrown at distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/SyncPluginsAction.java:296

                    plugins.add(info);

                    // Check for a version mismatch, unless it's an official plugin since we can upgrade them.
                    if (InstallPluginAction.OFFICIAL_PLUGINS.contains(info.getName())
                        && info.getElasticsearchVersion().toString().equals(Build.current().version()) == false) {
                        this.terminal.errorPrintln(
                            String.format(
                                Locale.ROOT,
                                "WARNING: plugin [%s] was built for Elasticsearch version %s but version %s is required",
                                info.getName(),
                                info.getElasticsearchVersion(),
                                Build.current().version()
                            )
                        );
                    }
                }
            }
        } catch (IOException e) {
            throw new PluginSyncException("Failed to list existing plugins", e);
        }

        return plugins;
    }

    /**
     * Returns a list of all elements in {@code left} that are not present in {@code right}.
     * <p>
     * Comparisons are based solely using {@link InstallablePlugin#getId()}.
     *
     * @param left the items that may be retained
     * @param right the items that may be removed
     * @return a list of the remaining elements
     */
    private static List<InstallablePlugin> difference(List<InstallablePlugin> left, List<InstallablePlugin> right) {
        return left.stream().filter(eachDescriptor -> {
            final String id = eachDescriptor.getId();
            return right.stream().anyMatch(p -> p.getId().equals(id)) == false;

View on GitHub (pinned to db6a809a66)

Solutions

  1. Check the caused-by IOException in the stack trace for the exact path that failed.
  2. ls -la $ES_HOME/plugins/* and confirm each plugin dir is readable by the ES user and contains plugin-descriptor.properties.
  3. Remove and reinstall the offending plugin via elasticsearch-plugin install <name>.
  4. Fix filesystem permissions: chown -R elasticsearch:elasticsearch $ES_HOME/plugins.
Defensive patterns

Strategy: try-catch

Validate before calling

for (Path p : env.pluginsDir().toFile().listFiles()) {
    Path desc = p.toPath().resolve("plugin-descriptor.properties");
    if (Files.notExists(desc) || Files.isReadable(desc) == false) {
        // skip or report before invoking sync
    }
}

Try / catch

try {
    action.execute();
} catch (PluginSyncException e) {
    // SyncPluginsCliProvider already wraps this; log caused-by IOException for the failing path.
    throw new RuntimeException("Plugin sync failed: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: A plugin subdirectory under plugins/ is unreadable (permissions), a plugin descriptor .properties file is missing/corrupt, or the directory stream hits an I/O error (NFS hiccup, broken symlink, SELinux denial).

Common situations: Partial plugin install left a half-extracted .zip; plugin dir owned by root but ES runs as a different user; NFS/network mount flakiness; manually copied a plugin without its plugin-descriptor.properties.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/8794f061e366698f. Report an issue: GitHub.