{"record":{"id":"0520bf2b57af7757","repo":"elastic/elasticsearch","slug":"cannot-have-null-or-empty-ids-in-elasticsearch-pl","errorCode":null,"errorMessage":"Cannot have null or empty IDs in [elasticsearch-plugins.yml]","messagePattern":"Cannot have null or empty IDs in \\[elasticsearch-plugins\\.yml\\]","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/PluginsConfig.java","lineNumber":68,"sourceCode":"        this.proxy = proxy;\n    }\n\n    /**\n     * Validate this instance. For example:\n     * <ul>\n     *     <li>All {@link InstallablePlugin}s must have IDs</li>\n     *     <li>Any proxy must be well-formed.</li>\n     *     <li>Unofficial plugins must have locations</li>\n     * </ul>\n     *\n     * @param officialPlugins the plugins that can be installed by name only\n     * @param migratedPlugins plugins that were once official but have since become modules. These\n     *                        plugin IDs can still be specified, but do nothing.\n     * @throws PluginSyncException if validation problems are found\n     */\n    public void validate(Set<String> officialPlugins, Set<String> migratedPlugins) throws PluginSyncException {\n        if (this.plugins.stream().anyMatch(each -> each == null || Strings.isNullOrBlank(each.getId()))) {\n            throw new RuntimeException(\"Cannot have null or empty IDs in [elasticsearch-plugins.yml]\");\n        }\n\n        final Set<String> uniquePluginIds = new HashSet<>();\n        for (final InstallablePlugin plugin : plugins) {\n            if (uniquePluginIds.add(plugin.getId()) == false) {\n                throw new PluginSyncException(\"Duplicate plugin ID [\" + plugin.getId() + \"] found in [elasticsearch-plugins.yml]\");\n            }\n        }\n\n        for (InstallablePlugin plugin : this.plugins) {\n            if (officialPlugins.contains(plugin.getId()) == false\n                && migratedPlugins.contains(plugin.getId()) == false\n                && plugin.getLocation() == null) {\n                throw new PluginSyncException(\n                    \"Must specify location for non-official plugin [\" + plugin.getId() + \"] in [elasticsearch-plugins.yml]\"\n                );\n            }\n        }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/PluginsConfig.java#L50-L86","documentation":"Thrown by PluginsConfig.validate when any InstallablePlugin in elasticsearch-plugins.yml is null or has a null/blank id. Note this is a generic RuntimeException (not a PluginSyncException like the sibling checks), so it propagates with no dedicated exit code. It is the first validation gate before duplicate- and location-checking.","triggerScenarios":"Parsing elasticsearch-plugins.yml yields a plugins list where at least one entry is null or its `id` field is missing/whitespace. The stream `anyMatch(each -> each == null || Strings.isNullOrBlank(each.getId()))` returns true and the exception fires.","commonSituations":"Hand-edited elasticsearch-plugins.yml with a list item missing the `id:` key; YAML parser produced a null entry from `- ` with no body; copy-paste of a plugin block that dropped the id line.","solutions":["Open elasticsearch-plugins.yml and ensure every entry under `plugins:` has a non-empty `id:` value.","Validate the YAML before deploying: `yq '.plugins[].id' elasticsearch-plugins.yml` should print one id per entry with no blanks.","If a list slot is intentionally empty, remove the empty `-` item entirely."],"exampleFix":"# before:\nplugins:\n  - id: analysis-icu\n  - location: file:///opt/x   # missing id -> error\n# after:\nplugins:\n  - id: analysis-icu\n  - id: custom-x\n    location: file:///opt/x","handlingStrategy":"validation","validationCode":"// Pre-validate the yml before invoking PluginsConfig.validate.\nfor (InstallablePlugin p : parsed.getPlugins()) {\n    if (p == null || Strings.isNullOrBlank(p.getId())) {\n        throw new IllegalArgumentException(\"Every plugin needs a non-blank id\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Lint elasticsearch-plugins.yml in CI: every `- id:` must have a value.","Use a schema validator (e.g. JSON Schema for the YAML) before deploy.","Generate the file from a templating system that always sets id."],"tags":["plugins-config","validation","yaml","plugin-cli"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}