elastic/elasticsearch · error · IllegalArgumentException

Invalid version format: '{s}'. Should be {pattern}

Error message

Invalid version format: '{s}'. Should be {pattern}

What it means

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.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/QualifiedVersion.java:43

 */
public record QualifiedVersion(int major, int minor, int revision, Qualifier qualifier) implements Comparable<QualifiedVersion> {

    private static final Pattern pattern = Pattern.compile(
        "^v? (\\d+) \\. (\\d+) \\. (\\d+) (?: - (alpha\\d+ | beta\\d+ | rc\\d+ | SNAPSHOT ) )? $",
        Pattern.COMMENTS
    );

    /**
     * Parses the supplied string into an object.
     *
     * @param s a version string in strict semver
     * @return a new instance
     */
    public static QualifiedVersion of(final String s) {
        Objects.requireNonNull(s);
        Matcher matcher = pattern.matcher(s);
        if (matcher.matches() == false) {
            throw new IllegalArgumentException("Invalid version format: '" + s + "'. Should be " + pattern);
        }

        return new QualifiedVersion(
            Integer.parseInt(matcher.group(1)),
            Integer.parseInt(matcher.group(2)),
            Integer.parseInt(matcher.group(3)),
            matcher.group(4) == null ? null : Qualifier.of(matcher.group(4))
        );
    }

    @Override
    public String toString() {
        return String.format(Locale.ROOT, "%d.%d.%d%s", major, minor, revision, qualifier == null ? "" : "-" + qualifier);
    }

    public boolean hasQualifier() {
        return qualifier != null;
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. 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').
  2. Check the echoed `pattern` in the message for the exact accepted shape and align the input.
  3. If the input legitimately carries build metadata, parse/strip it before calling QualifiedVersion.of.
  4. Add a unit test for the version string to catch regressions in the producing tool.

Example fix

// before
QualifiedVersion.of("8.0");
QualifiedVersion.of("8.0.0.1");
// after
QualifiedVersion.of("8.0.0");
QualifiedVersion.of("8.0.1");
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern STRICT_SEMVER =
    Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(\\p{Alnum}+))?$");
if (STRICT_SEMVER.matcher(s).matches() == false) {
    throw new IllegalArgumentException("Not strict semver: " + s);
}

Type guard

static boolean isQualifiedVersion(String s) {
    return s != null && STRICT_SEMVER.matcher(s).matches();
}

Try / catch

try { QualifiedVersion v = QualifiedVersion.of(s); }
catch (IllegalArgumentException e) {
    // normalize s (strip build metadata) then retry, or surface to the user
    throw e;
}

Prevention

When it happens

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

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

Related errors


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