elastic/elasticsearch · critical · IllegalStateException
Expected elasticsearch version to be numbers only of the for
Error message
Expected elasticsearch version to be numbers only of the form X.Y.Z but it was: ${elasticsearch} What it means
After confirming the elasticsearch property exists, the loader validates it against the strict regex [0-9]+\.[0-9]+\.[0-9]+ and rejects anything that is not a bare X.Y.Z. This prevents suffixes like -SNAPSHOT or -rc1 from leaking into the base version, since those are appended programmatically from the qualifier and build.snapshot sysprops.
Source
Thrown at build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/VersionPropertiesLoader.java:38
// Define this here because we need it early.
public class VersionPropertiesLoader {
static Properties loadBuildSrcVersion(File input, ProviderFactory providerFactory) throws IOException {
Properties props = new Properties();
try (InputStream is = new FileInputStream(input)) {
props.load(is);
}
loadBuildSrcVersion(props, providerFactory);
return props;
}
protected static void loadBuildSrcVersion(Properties loadedProps, ProviderFactory providers) {
String elasticsearch = loadedProps.getProperty("elasticsearch");
if (elasticsearch == null) {
throw new IllegalStateException("Elasticsearch version is missing from properties.");
}
if (elasticsearch.matches("[0-9]+\\.[0-9]+\\.[0-9]+") == false) {
throw new IllegalStateException(
"Expected elasticsearch version to be numbers only of the form X.Y.Z but it was: " +
elasticsearch
);
}
String qualifier = providers.systemProperty("build.version_qualifier")
.getOrElse("");
if (qualifier.isEmpty() == false) {
if (qualifier.matches("(alpha|beta|rc)\\d+") == false) {
throw new IllegalStateException("Invalid qualifier: " + qualifier);
}
elasticsearch += "-" + qualifier;
}
final String buildSnapshotSystemProperty = providers.systemProperty("build.snapshot")
.getOrElse("true");
switch (buildSnapshotSystemProperty) {
case "true":
elasticsearch += "-SNAPSHOT";
break;View on GitHub (pinned to db6a809a66)
Solutions
- Edit version.properties so elasticsearch is a bare X.Y.Z, e.g. `elasticsearch=9.0.0`.
- Remove any -SNAPSHOT, -rc1, or v prefix from the property; pass those via -Dbuild.version_qualifier and -Dbuild.snapshot instead.
- Re-generate the file from the release tooling rather than editing it by hand.
Example fix
// before elasticsearch=9.0.0-SNAPSHOT // after elasticsearch=9.0.0
Defensive patterns
Strategy: validation
Validate before calling
String v = props.getProperty("elasticsearch");
if (v == null || !v.matches("[0-9]+\\.[0-9]+\\.[0-9]+")) {
throw new GradleException("elasticsearch version must be bare X.Y.Z, got: " + v);
} Prevention
- Keep the base version as X.Y.Z only; pass -SNAPSHOT and qualifiers via sysprops.
- Validate version.properties in CI with a regex check.
- Never paste a full release string into the elasticsearch property.
When it happens
Trigger: loadBuildSrcVersion sees an elasticsearch value such as 9.0.0-SNAPSHOT, 9.0, v9.0.0, or 9.0.0.1 — anything not matching exactly three dot-separated numeric groups.
Common situations: Someone hand-edited version.properties to include the snapshot suffix; a release script wrote a full qualified version into the base property; a branch merge introduced a malformed version string; a downstream fork pinned a two-component version.
Related errors
- Elasticsearch version is missing from properties.
- Invalid qualifier: ${qualifier}
- build.snapshot was set to [${buildSnapshotSystemProperty}] b
- Cannot load VersionPropertiesBuildService
- Sysprop [${property}] must be [true] or [false] but was [${p
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/269ff3916a559901.
Report an issue: GitHub.