{"record":{"id":"b07dab75ee231cf6","repo":"elastic/elasticsearch","slug":"invalid-version-format-s-should-be-pattern","errorCode":null,"errorMessage":"Invalid version format: '{s}'. Should be {pattern}","messagePattern":"Invalid version format: '(.+?)'\\. Should be (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/QualifiedVersion.java","lineNumber":43,"sourceCode":" */\npublic record QualifiedVersion(int major, int minor, int revision, Qualifier qualifier) implements Comparable<QualifiedVersion> {\n\n    private static final Pattern pattern = Pattern.compile(\n        \"^v? (\\\\d+) \\\\. (\\\\d+) \\\\. (\\\\d+) (?: - (alpha\\\\d+ | beta\\\\d+ | rc\\\\d+ | SNAPSHOT ) )? $\",\n        Pattern.COMMENTS\n    );\n\n    /**\n     * Parses the supplied string into an object.\n     *\n     * @param s a version string in strict semver\n     * @return a new instance\n     */\n    public static QualifiedVersion of(final String s) {\n        Objects.requireNonNull(s);\n        Matcher matcher = pattern.matcher(s);\n        if (matcher.matches() == false) {\n            throw new IllegalArgumentException(\"Invalid version format: '\" + s + \"'. Should be \" + pattern);\n        }\n\n        return new QualifiedVersion(\n            Integer.parseInt(matcher.group(1)),\n            Integer.parseInt(matcher.group(2)),\n            Integer.parseInt(matcher.group(3)),\n            matcher.group(4) == null ? null : Qualifier.of(matcher.group(4))\n        );\n    }\n\n    @Override\n    public String toString() {\n        return String.format(Locale.ROOT, \"%d.%d.%d%s\", major, minor, revision, qualifier == null ? \"\" : \"-\" + qualifier);\n    }\n\n    public boolean hasQualifier() {\n        return qualifier != null;\n    }","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/QualifiedVersion.java#L25-L61","documentation":"Thrown by QualifiedVersion.of when the supplied string does not match the strict semver pattern held in `pattern`. The matcher requires a precise major.minor.patch(+qualifier) shape; any deviation — missing component, extra segments, non-numeric parts — fails matcher.matches() and the task rejects the input with the expected pattern echoed in the message.","triggerScenarios":"QualifiedVersion.of(s) is called with a string that isn't strict semver: missing patch (e.g. '8.0'), extra build metadata formatted wrong, a non-numeric component, leading zeros, or a qualifier that doesn't match Qualifier.of's accepted set. The pattern is matched before any parsing, so the failure is purely format validation.","commonSituations":"Passing a Maven-style version ('8.0.0-SNAPSHOT' may be valid, but '8.0' or '8.0.0.1' is not); a version string sourced from a git tag/env var that includes extra metadata; copy-paste error; mixing qualified and unqualified semver formats across release tooling.","solutions":["Reformat the version string to strict major.minor.patch with an optional qualifier that Qualifier.of accepts (e.g. '8.0.0', '8.0.0-alpha1', '8.0.0-rc1').","Check the echoed `pattern` in the message for the exact accepted shape and align the input.","If the input legitimately carries build metadata, parse/strip it before calling QualifiedVersion.of.","Add a unit test for the version string to catch regressions in the producing tool."],"exampleFix":"// before\nQualifiedVersion.of(\"8.0\");\nQualifiedVersion.of(\"8.0.0.1\");\n// after\nQualifiedVersion.of(\"8.0.0\");\nQualifiedVersion.of(\"8.0.1\");","handlingStrategy":"validation","validationCode":"private static final Pattern STRICT_SEMVER =\n    Pattern.compile(\"^(\\\\d+)\\\\.(\\\\d+)\\\\.(\\\\d+)(?:-(\\\\p{Alnum}+))?$\");\nif (STRICT_SEMVER.matcher(s).matches() == false) {\n    throw new IllegalArgumentException(\"Not strict semver: \" + s);\n}","typeGuard":"static boolean isQualifiedVersion(String s) {\n    return s != null && STRICT_SEMVER.matcher(s).matches();\n}","tryCatchPattern":"try { QualifiedVersion v = QualifiedVersion.of(s); }\ncatch (IllegalArgumentException e) {\n    // normalize s (strip build metadata) then retry, or surface to the user\n    throw e;\n}","preventionTips":["Normalize version strings to strict semver before calling QualifiedVersion.of.","Validate versions from external sources (git tags, env vars) at the boundary.","Keep release tooling consistent — don't mix Maven and strict semver shapes."],"tags":["build","gradle","release","versioning","validation"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}