elastic/elasticsearch · error · IllegalArgumentException

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

Error message

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

What it means

Version.fromString() throws IllegalArgumentException when the input does not match the parsing regex. In STRICT mode (default), the pattern is (\d+)\.(\d+)\.(\d+)(?:-(alpha\d+|beta\d+|rc\d+|SNAPSHOT))? — i.e., major.minor.revision with an optional qualifier of alpha<N>, beta<N>, rc<N>, or SNAPSHOT. In RELAXED mode, a broader pattern allows an optional v prefix, optional revision, and arbitrary alphanumeric suffixes.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/Version.java:74

        // currently qualifier is not taken into account
        this.id = major * 10000000 + minor * 100000 + revision * 1000;

        this.qualifier = qualifier;
    }

    public static Version fromString(final String s) {
        return fromString(s, Mode.STRICT);
    }

    public static Version fromString(final String s, final Mode mode) {
        Objects.requireNonNull(s);
        Matcher matcher = mode == Mode.STRICT ? pattern.matcher(s) : relaxedPattern.matcher(s);
        if (matcher.matches() == false) {
            String expected = mode == Mode.STRICT
                ? "major.minor.revision[-(alpha|beta|rc)Number|-SNAPSHOT]"
                : "major.minor.revision[-extra]";
            throw new IllegalArgumentException("Invalid version format: '" + s + "'. Should be " + expected);
        }

        String major = matcher.group(1);
        String minor = matcher.group(2);
        String revision = matcher.group(3);
        String qualifier = matcher.group(4);

        return new Version(Integer.parseInt(major), Integer.parseInt(minor), revision == null ? 0 : Integer.parseInt(revision), qualifier);
    }

    @Override
    public String toString() {
        return getMajor() + "." + getMinor() + "." + getRevision();
    }

    public boolean before(Version compareTo) {
        return id < compareTo.getId();
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Reformat the version to major.minor.revision with an optional -(alpha|beta|rc)N or -SNAPSHOT suffix for STRICT parsing.
  2. If the string uses a broader format (v prefix, custom suffix), parse with Version.fromString(s, Mode.RELAXED).
  3. Strip build metadata (+...) and any non-conforming qualifier before parsing.
  4. Validate with a regex pre-check if version strings come from external/untrusted sources.

Example fix

// before
Version v = Version.fromString("1.2.3-stable"); // throws in STRICT

// after (option 1: conform)
Version v = Version.fromString("1.2.3");
// after (option 2: relaxed)
Version v = Version.fromString("1.2.3-stable", Version.Mode.RELAXED);
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern STRICT = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-(alpha\\d+|beta\\d+|rc\\d+|SNAPSHOT))?");
if (!STRICT.matcher(version).matches() && !RELAXED.matcher(version).matches()) {
    throw new IllegalArgumentException("Version '" + version + "' matches neither strict nor relaxed format");
}
Version.fromString(version, STRICT.matcher(version).matches() ? Version.Mode.STRICT : Version.Mode.RELAXED);

Type guard

static boolean isParsableVersion(String s) {
  return Pattern.compile("(\\\\d+)\\\\.(\\\\d+)\\\\.(\\\\d+)(?:-(alpha\\\\d+|beta\\\\d+|rc\\\\d+|SNAPSHOT))?").matcher(s).matches();
}

Try / catch

try { Version v = Version.fromString(s); } catch (IllegalArgumentException e) { /* try relaxed, or sanitize the string */ Version v = Version.fromString(s, Version.Mode.RELAXED); }

Prevention

When it happens

Trigger: Calling Version.fromString(s) (STRICT) or Version.fromString(s, Mode.RELAXED) with a non-conforming string. STRICT rejects: missing revision (1.2), spaces, unknown qualifiers (1.2.3-stable, 1.2.3.rc1), extra components (1.2.3.4), build metadata (1.2.3+build5).

Common situations: Parsing a dependency version string that uses a non-Elasticsearch format (SemVer build metadata, CalVer, custom suffixes like -dev, -RELEASE); passing a Git tag like v1.2.3 in STRICT mode (the v prefix is only allowed in RELAXED); a null or empty string (null throws NPE earlier via Objects.requireNonNull); typos in version config.

Related errors


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