{"record":{"id":"8794f061e366698f","repo":"elastic/elasticsearch","slug":"failed-to-list-existing-plugins","errorCode":null,"errorMessage":"Failed to list existing plugins","messagePattern":"Failed to list existing plugins","errorType":"exception","errorClass":"PluginSyncException","httpStatus":null,"severity":"error","filePath":"distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/SyncPluginsAction.java","lineNumber":296,"sourceCode":"                    plugins.add(info);\n\n                    // Check for a version mismatch, unless it's an official plugin since we can upgrade them.\n                    if (InstallPluginAction.OFFICIAL_PLUGINS.contains(info.getName())\n                        && info.getElasticsearchVersion().toString().equals(Build.current().version()) == false) {\n                        this.terminal.errorPrintln(\n                            String.format(\n                                Locale.ROOT,\n                                \"WARNING: plugin [%s] was built for Elasticsearch version %s but version %s is required\",\n                                info.getName(),\n                                info.getElasticsearchVersion(),\n                                Build.current().version()\n                            )\n                        );\n                    }\n                }\n            }\n        } catch (IOException e) {\n            throw new PluginSyncException(\"Failed to list existing plugins\", e);\n        }\n\n        return plugins;\n    }\n\n    /**\n     * Returns a list of all elements in {@code left} that are not present in {@code right}.\n     * <p>\n     * Comparisons are based solely using {@link InstallablePlugin#getId()}.\n     *\n     * @param left the items that may be retained\n     * @param right the items that may be removed\n     * @return a list of the remaining elements\n     */\n    private static List<InstallablePlugin> difference(List<InstallablePlugin> left, List<InstallablePlugin> right) {\n        return left.stream().filter(eachDescriptor -> {\n            final String id = eachDescriptor.getId();\n            return right.stream().anyMatch(p -> p.getId().equals(id)) == false;","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/SyncPluginsAction.java#L278-L314","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check the caused-by IOException in the stack trace for the exact path that failed.","ls -la $ES_HOME/plugins/* and confirm each plugin dir is readable by the ES user and contains plugin-descriptor.properties.","Remove and reinstall the offending plugin via elasticsearch-plugin install <name>.","Fix filesystem permissions: chown -R elasticsearch:elasticsearch $ES_HOME/plugins."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"for (Path p : env.pluginsDir().toFile().listFiles()) {\n    Path desc = p.toPath().resolve(\"plugin-descriptor.properties\");\n    if (Files.notExists(desc) || Files.isReadable(desc) == false) {\n        // skip or report before invoking sync\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    action.execute();\n} catch (PluginSyncException e) {\n    // SyncPluginsCliProvider already wraps this; log caused-by IOException for the failing path.\n    throw new RuntimeException(\"Plugin sync failed: \" + e.getMessage(), e);\n}","preventionTips":["Keep plugins/ owned by and readable for the ES user.","Avoid partial plugin installs — always install/remove via elasticsearch-plugin CLI.","Periodically audit each plugin dir has a valid plugin-descriptor.properties."],"tags":["plugins","io","permissions","filesystem","sync-plugins"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}