elastic/elasticsearch · error · IllegalArgumentException

Invalid qualifier [{qualifier}] passed

Error message

Invalid qualifier [{qualifier}] passed

What it means

Thrown by QualifiedVersion.Qualifier.of(String) when the qualifier string is neither the literal "SNAPSHOT" nor matches ^(alpha|beta|rc)(\d+)$. The code comment itself admits "This shouldn't happen" because the caller is expected to pre-validate the qualifier format against the same regex before invoking of(). It is therefore a programming-contract violation, not a user-input error.

Source

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

    private record Qualifier(QualifierLevel level, int number) implements Comparable<Qualifier> {

        private static final Comparator<Qualifier> COMPARATOR = Comparator.comparing((Qualifier p) -> p.level).thenComparing(p -> p.number);

        private static Qualifier of(String qualifier) {
            if ("SNAPSHOT".equals(qualifier)) {
                return new Qualifier(QualifierLevel.SNAPSHOT, 0);
            }

            Pattern pattern = Pattern.compile("^(alpha|beta|rc)(\\d+)$");
            Matcher matcher = pattern.matcher(qualifier);
            if (matcher.find()) {
                String level = matcher.group(1);
                int number = Integer.parseInt(matcher.group(2));
                return new Qualifier(QualifierLevel.valueOf(level), number);
            } else {
                // This shouldn't happen - we check the format before this is called
                throw new IllegalArgumentException("Invalid qualifier [" + qualifier + "] passed");
            }
        }

        @Override
        public int compareTo(Qualifier other) {
            return COMPARATOR.compare(this, other);
        }

        @Override
        public String toString() {
            return level == QualifierLevel.SNAPSHOT ? level.name() : level.name() + number;
        }
    }
}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Pre-validate the qualifier with the same regex ^(alpha|beta|rc)(\d+)$ before constructing the QualifiedVersion, and reject or normalize it earlier.
  2. Correct the qualifier string the caller is passing: use lowercase alpha/beta/rc immediately followed by digits, or the literal SNAPSHOT.
  3. If a new qualifier form is intentionally being introduced, extend both the regex in of() and the QualifierLevel enum together so the parse and enum stay in sync.

Example fix

// before
new QualifiedVersion("8.10.0-BETA1");

// after
new QualifiedVersion("8.10.0-beta1");
Defensive patterns

Strategy: validation

Validate before calling

// Validate a qualifier before constructing QualifiedVersion
private static final Pattern QUAL = Pattern.compile("^(SNAPSHOT|(alpha|beta|rc)\\d+)$");
static boolean isValidQualifier(String q) {
    return q != null && QUAL.matcher(q).matches();
}
// guard:
if (!isValidQualifier(qualifier)) {
    throw new IllegalArgumentException("Refusing qualifier " + qualifier + "; expected SNAPSHOT or alpha|beta|rc + digits");
}

Prevention

When it happens

Trigger: Calling QualifiedVersion construction with a version string whose qualifier segment is something other than SNAPSHOT, alphaN, betaN, rcN — e.g. "8.10.0-ga", "9.0.0-BETA1", "8.5.0-rc" (missing number), or a qualifier with unexpected casing.

Common situations: A release script or Gradle property passes a malformed or differently-cased pre-release tag; a version constant is edited by hand; an upstream caller was updated to support a new qualifier form (e.g. "rc" without a digit) without loosening the regex in QualifiedVersion.

Related errors


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