{"record":{"id":"69cf297e3b8efe00","repo":"elastic/elasticsearch","slug":"invalid-version-format-should-be","errorCode":null,"errorMessage":"Invalid version format: '{}'. Should be {}","messagePattern":"Invalid version format: '(.+?)'\\. Should be (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/Version.java","lineNumber":74,"sourceCode":"\n        // currently qualifier is not taken into account\n        this.id = major * 10000000 + minor * 100000 + revision * 1000;\n\n        this.qualifier = qualifier;\n    }\n\n    public static Version fromString(final String s) {\n        return fromString(s, Mode.STRICT);\n    }\n\n    public static Version fromString(final String s, final Mode mode) {\n        Objects.requireNonNull(s);\n        Matcher matcher = mode == Mode.STRICT ? pattern.matcher(s) : relaxedPattern.matcher(s);\n        if (matcher.matches() == false) {\n            String expected = mode == Mode.STRICT\n                ? \"major.minor.revision[-(alpha|beta|rc)Number|-SNAPSHOT]\"\n                : \"major.minor.revision[-extra]\";\n            throw new IllegalArgumentException(\"Invalid version format: '\" + s + \"'. Should be \" + expected);\n        }\n\n        String major = matcher.group(1);\n        String minor = matcher.group(2);\n        String revision = matcher.group(3);\n        String qualifier = matcher.group(4);\n\n        return new Version(Integer.parseInt(major), Integer.parseInt(minor), revision == null ? 0 : Integer.parseInt(revision), qualifier);\n    }\n\n    @Override\n    public String toString() {\n        return getMajor() + \".\" + getMinor() + \".\" + getRevision();\n    }\n\n    public boolean before(Version compareTo) {\n        return id < compareTo.getId();\n    }","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/Version.java#L56-L92","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Reformat the version to major.minor.revision with an optional -(alpha|beta|rc)N or -SNAPSHOT suffix for STRICT parsing.","If the string uses a broader format (v prefix, custom suffix), parse with Version.fromString(s, Mode.RELAXED).","Strip build metadata (+...) and any non-conforming qualifier before parsing.","Validate with a regex pre-check if version strings come from external/untrusted sources."],"exampleFix":"// before\nVersion v = Version.fromString(\"1.2.3-stable\"); // throws in STRICT\n\n// after (option 1: conform)\nVersion v = Version.fromString(\"1.2.3\");\n// after (option 2: relaxed)\nVersion v = Version.fromString(\"1.2.3-stable\", Version.Mode.RELAXED);","handlingStrategy":"validation","validationCode":"private static final Pattern STRICT = Pattern.compile(\"(\\\\d+)\\\\.(\\\\d+)\\\\.(\\\\d+)(?:-(alpha\\\\d+|beta\\\\d+|rc\\\\d+|SNAPSHOT))?\");\nif (!STRICT.matcher(version).matches() && !RELAXED.matcher(version).matches()) {\n    throw new IllegalArgumentException(\"Version '\" + version + \"' matches neither strict nor relaxed format\");\n}\nVersion.fromString(version, STRICT.matcher(version).matches() ? Version.Mode.STRICT : Version.Mode.RELAXED);","typeGuard":"static boolean isParsableVersion(String s) {\n  return Pattern.compile(\"(\\\\\\\\d+)\\\\\\\\.(\\\\\\\\d+)\\\\\\\\.(\\\\\\\\d+)(?:-(alpha\\\\\\\\d+|beta\\\\\\\\d+|rc\\\\\\\\d+|SNAPSHOT))?\").matcher(s).matches();\n}","tryCatchPattern":"try { Version v = Version.fromString(s); } catch (IllegalArgumentException e) { /* try relaxed, or sanitize the string */ Version v = Version.fromString(s, Version.Mode.RELAXED); }","preventionTips":["Conform to major.minor.revision with optional -(alpha|beta|rc)N or -SNAPSHOT for STRICT parsing.","Use Mode.RELAXED for v-prefixed tags or custom suffixes.","Strip build metadata (+...) before parsing.","Validate external version strings with a regex before passing to fromString."],"tags":["gradle","build-tools","version-parsing","validation"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}