elastic/elasticsearch · error · InvalidUserDataException

invalid deploymentTarget '{}', expected one of {}

Error message

invalid deploymentTarget '{}', expected one of {}

What it means

Thrown when deploymentTarget on an esplugin is not one of ALL, STATELESS_ONLY, STATEFUL_ONLY (the DEPLOYMENT_TARGETS set). Defaults to "ALL" when unset, so this only fires when explicitly set to an invalid value. deploymentTarget controls whether the plugin is loaded by stateful clusters, stateless clusters, or both.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/plugin/GeneratePluginPropertiesTask.java:135

        }

        Map<String, Object> props = new HashMap<>();
        props.put("name", getPluginName().get());
        props.put("description", getPluginDescription().get());
        props.put("version", getPluginVersion().get());
        props.put("elasticsearchVersion", getElasticsearchVersion().get());
        props.put("javaVersion", getJavaVersion().get());
        props.put("classname", classname);
        props.put("extendedPlugins", String.join(",", getExtendedPlugins().get()));
        props.put("hasNativeController", getHasNativeController().get());
        props.put("nativeControllerEnabledSettings", String.join(",", getNativeControllerEnabledSettings().get()));
        props.put("requiresKeystore", getRequiresKeystore().get());
        props.put("licensed", getIsLicensed().get());
        props.put("modulename", findModuleName());

        String deploymentTarget = getDeploymentTarget().getOrElse("ALL");
        if (DEPLOYMENT_TARGETS.contains(deploymentTarget) == false) {
            throw new InvalidUserDataException(
                "invalid deploymentTarget '" + deploymentTarget + "', expected one of " + DEPLOYMENT_TARGETS
            );
        }
        props.put("deploymentTarget", deploymentTarget);

        SimpleTemplateEngine engine = new SimpleTemplateEngine();
        Path outputFile = getOutputFile().get().getAsFile().toPath();
        Files.createDirectories(outputFile.getParent());
        try (
            var inputStream = GeneratePluginPropertiesTask.class.getResourceAsStream("/" + PROPERTIES_FILENAME);
            var reader = new BufferedReader(new InputStreamReader(inputStream));
            var writer = Files.newBufferedWriter(outputFile, StandardCharsets.UTF_8)
        ) {
            Template template = engine.createTemplate(reader);
            template.make(props).writeTo(writer);
        }
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Set deploymentTarget to exactly one of: 'ALL', 'STATELESS_ONLY', 'STATEFUL_ONLY' (uppercase, with _ONLY suffix).
  2. If unsure, omit deploymentTarget entirely — it defaults to 'ALL' and the plugin loads everywhere.
  3. Re-check DEPLOYMENT_TARGETS in GeneratePluginPropertiesTask if you are on a fork that extended the set.

Example fix

// before
esplugin {
  deploymentTarget = 'STATELESS'
}

// after
esplugin {
  deploymentTarget = 'STATELESS_ONLY'
}
Defensive patterns

Strategy: validation

Validate before calling

Set<String> allowed = Set.of("ALL", "STATELESS_ONLY", "STATEFUL_ONLY");
String target = deploymentTarget; // value to set
if (!allowed.contains(target)) {
    throw new IllegalArgumentException("deploymentTarget must be one of " + allowed);
}
esplugin { deploymentTarget = target }

Prevention

When it happens

Trigger: esplugin { deploymentTarget = 'STATELESS' } (missing _ONLY suffix), or any typo / case variation. The guard runs late in generatePropertiesFile after getDeploymentTarget().getOrElse("ALL").

Common situations: Migrating a plugin to support stateless mode and guessing the enum value, or using a value from an older/newer branch where the constant set differs.

Related errors


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