elastic/elasticsearch · error · RuntimeException

Cannot have null or empty IDs in [elasticsearch-plugins.yml]

Error message

Cannot have null or empty IDs in [elasticsearch-plugins.yml]

What it means

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.

Source

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

        this.proxy = proxy;
    }

    /**
     * Validate this instance. For example:
     * <ul>
     *     <li>All {@link InstallablePlugin}s must have IDs</li>
     *     <li>Any proxy must be well-formed.</li>
     *     <li>Unofficial plugins must have locations</li>
     * </ul>
     *
     * @param officialPlugins the plugins that can be installed by name only
     * @param migratedPlugins plugins that were once official but have since become modules. These
     *                        plugin IDs can still be specified, but do nothing.
     * @throws PluginSyncException if validation problems are found
     */
    public void validate(Set<String> officialPlugins, Set<String> migratedPlugins) throws PluginSyncException {
        if (this.plugins.stream().anyMatch(each -> each == null || Strings.isNullOrBlank(each.getId()))) {
            throw new RuntimeException("Cannot have null or empty IDs in [elasticsearch-plugins.yml]");
        }

        final Set<String> uniquePluginIds = new HashSet<>();
        for (final InstallablePlugin plugin : plugins) {
            if (uniquePluginIds.add(plugin.getId()) == false) {
                throw new PluginSyncException("Duplicate plugin ID [" + plugin.getId() + "] found in [elasticsearch-plugins.yml]");
            }
        }

        for (InstallablePlugin plugin : this.plugins) {
            if (officialPlugins.contains(plugin.getId()) == false
                && migratedPlugins.contains(plugin.getId()) == false
                && plugin.getLocation() == null) {
                throw new PluginSyncException(
                    "Must specify location for non-official plugin [" + plugin.getId() + "] in [elasticsearch-plugins.yml]"
                );
            }
        }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Open elasticsearch-plugins.yml and ensure every entry under `plugins:` has a non-empty `id:` value.
  2. Validate the YAML before deploying: `yq '.plugins[].id' elasticsearch-plugins.yml` should print one id per entry with no blanks.
  3. If a list slot is intentionally empty, remove the empty `-` item entirely.

Example fix

# before:
plugins:
  - id: analysis-icu
  - location: file:///opt/x   # missing id -> error
# after:
plugins:
  - id: analysis-icu
  - id: custom-x
    location: file:///opt/x
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate the yml before invoking PluginsConfig.validate.
for (InstallablePlugin p : parsed.getPlugins()) {
    if (p == null || Strings.isNullOrBlank(p.getId())) {
        throw new IllegalArgumentException("Every plugin needs a non-blank id");
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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