{"record":{"id":"868615928449940e","repo":"elastic/elasticsearch","slug":"invalid-qualifier-qualifier-passed","errorCode":null,"errorMessage":"Invalid qualifier [{qualifier}] passed","messagePattern":"Invalid qualifier \\[(.+?)\\] passed","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/QualifiedVersion.java","lineNumber":109,"sourceCode":"\n    private record Qualifier(QualifierLevel level, int number) implements Comparable<Qualifier> {\n\n        private static final Comparator<Qualifier> COMPARATOR = Comparator.comparing((Qualifier p) -> p.level).thenComparing(p -> p.number);\n\n        private static Qualifier of(String qualifier) {\n            if (\"SNAPSHOT\".equals(qualifier)) {\n                return new Qualifier(QualifierLevel.SNAPSHOT, 0);\n            }\n\n            Pattern pattern = Pattern.compile(\"^(alpha|beta|rc)(\\\\d+)$\");\n            Matcher matcher = pattern.matcher(qualifier);\n            if (matcher.find()) {\n                String level = matcher.group(1);\n                int number = Integer.parseInt(matcher.group(2));\n                return new Qualifier(QualifierLevel.valueOf(level), number);\n            } else {\n                // This shouldn't happen - we check the format before this is called\n                throw new IllegalArgumentException(\"Invalid qualifier [\" + qualifier + \"] passed\");\n            }\n        }\n\n        @Override\n        public int compareTo(Qualifier other) {\n            return COMPARATOR.compare(this, other);\n        }\n\n        @Override\n        public String toString() {\n            return level == QualifierLevel.SNAPSHOT ? level.name() : level.name() + number;\n        }\n    }\n}\n","sourceCodeStart":91,"sourceCodeEnd":124,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/QualifiedVersion.java#L91-L124","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew QualifiedVersion(\"8.10.0-BETA1\");\n\n// after\nnew QualifiedVersion(\"8.10.0-beta1\");","handlingStrategy":"validation","validationCode":"// Validate a qualifier before constructing QualifiedVersion\nprivate static final Pattern QUAL = Pattern.compile(\"^(SNAPSHOT|(alpha|beta|rc)\\\\d+)$\");\nstatic boolean isValidQualifier(String q) {\n    return q != null && QUAL.matcher(q).matches();\n}\n// guard:\nif (!isValidQualifier(qualifier)) {\n    throw new IllegalArgumentException(\"Refusing qualifier \" + qualifier + \"; expected SNAPSHOT or alpha|beta|rc + digits\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["release-tooling","version-parsing","precondition","gradle"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}