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
- Pre-validate the qualifier with the same regex ^(alpha|beta|rc)(\d+)$ before constructing the QualifiedVersion, and reject or normalize it earlier.
- Correct the qualifier string the caller is passing: use lowercase alpha/beta/rc immediately followed by digits, or the literal SNAPSHOT.
- 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
- Keep the qualifier regex in exactly one place and have both the pre-check and of() reference it.
- Lowercase and digit-stripping normalization should happen before QualifiedVersion construction.
- Add a unit test enumerating every accepted qualifier form to lock the contract.
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
- Invalid version format: '{}'. Should be {}
- Failed to load {EXTERNAL_SOURCES_CONFIG}
- Release version not specified
- No version tags specified
- Unknown version type {key}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/868615928449940e.
Report an issue: GitHub.