{"record":{"id":"269ff3916a559901","repo":"elastic/elasticsearch","slug":"expected-elasticsearch-version-to-be-numbers-only","errorCode":null,"errorMessage":"Expected elasticsearch version to be numbers only of the form  X.Y.Z but it was: ${elasticsearch}","messagePattern":"Expected elasticsearch version to be numbers only of the form  X\\.Y\\.Z but it was: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/VersionPropertiesLoader.java","lineNumber":38,"sourceCode":"\n// Define this here because we need it early.\npublic class VersionPropertiesLoader {\n    static Properties loadBuildSrcVersion(File input, ProviderFactory providerFactory) throws IOException {\n        Properties props = new Properties();\n        try (InputStream is = new FileInputStream(input)) {\n            props.load(is);\n        }\n        loadBuildSrcVersion(props, providerFactory);\n        return props;\n    }\n\n    protected static void loadBuildSrcVersion(Properties loadedProps, ProviderFactory providers) {\n        String elasticsearch = loadedProps.getProperty(\"elasticsearch\");\n        if (elasticsearch == null) {\n            throw new IllegalStateException(\"Elasticsearch version is missing from properties.\");\n        }\n        if (elasticsearch.matches(\"[0-9]+\\\\.[0-9]+\\\\.[0-9]+\") == false) {\n            throw new IllegalStateException(\n                    \"Expected elasticsearch version to be numbers only of the form  X.Y.Z but it was: \" +\n                            elasticsearch\n            );\n        }\n        String qualifier = providers.systemProperty(\"build.version_qualifier\")\n                .getOrElse(\"\");\n        if (qualifier.isEmpty() == false) {\n            if (qualifier.matches(\"(alpha|beta|rc)\\\\d+\") == false) {\n                throw new IllegalStateException(\"Invalid qualifier: \" + qualifier);\n            }\n            elasticsearch += \"-\" + qualifier;\n        }\n        final String buildSnapshotSystemProperty = providers.systemProperty(\"build.snapshot\")\n                .getOrElse(\"true\");\n        switch (buildSnapshotSystemProperty) {\n            case \"true\":\n                elasticsearch += \"-SNAPSHOT\";\n                break;","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/VersionPropertiesLoader.java#L20-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nelasticsearch=9.0.0-SNAPSHOT\n// after\nelasticsearch=9.0.0","handlingStrategy":"validation","validationCode":"String v = props.getProperty(\"elasticsearch\");\nif (v == null || !v.matches(\"[0-9]+\\\\.[0-9]+\\\\.[0-9]+\")) {\n    throw new GradleException(\"elasticsearch version must be bare X.Y.Z, got: \" + v);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["gradle","build-config","version-properties","validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}