{"record":{"id":"63eef7725e967d16","repo":"elastic/elasticsearch","slug":"found-src-dir-sourcesetname-for-java-versio","errorCode":null,"errorMessage":"Found src dir '${sourcesetName}' for Java ${version} but multi-release jar sourceset should have version ${minJavaVersion} or greater","messagePattern":"Found src dir '(.+?)' for Java (.+?) but multi-release jar sourceset should have version (.+?) or greater","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/MrjarPlugin.java","lineNumber":243,"sourceCode":"        project.getTasks().named(\"check\").configure(checkTask -> checkTask.dependsOn(testTaskProvider));\n    }\n\n    private static List<Integer> findSourceVersions(Project project, int minJavaVersion) {\n        var srcDir = project.getProjectDir().toPath().resolve(\"src\");\n        List<Integer> versions = new ArrayList<>();\n        try (var subdirStream = Files.list(srcDir)) {\n            for (Path sourceSetPath : subdirStream.toList()) {\n                assert Files.isDirectory(sourceSetPath);\n                String sourcesetName = sourceSetPath.getFileName().toString();\n                Matcher sourcesetMatcher = MRJAR_SOURCESET_PATTERN.matcher(sourcesetName);\n                if (sourcesetMatcher.matches()) {\n                    int version = Integer.parseInt(sourcesetMatcher.group(1));\n                    if (version < minJavaVersion) {\n                        // NOTE: We allow mainNN for the min java version so that incubating modules can be used without warnings.\n                        // It is a workaround for https://bugs.openjdk.org/browse/JDK-8187591. Once min java is 22, we\n                        // can use the SuppressWarnings(\"preview\") in the code using incubating modules and this check\n                        // can change to <=\n                        throw new IllegalArgumentException(\n                            \"Found src dir '\"\n                                + sourcesetName\n                                + \"' for Java \"\n                                + version\n                                + \" but multi-release jar sourceset should have version \"\n                                + minJavaVersion\n                                + \" or greater\"\n                        );\n                    }\n                    versions.add(version);\n                }\n            }\n        } catch (IOException e) {\n            throw new UncheckedIOException(e);\n        }\n\n        Collections.sort(versions);\n        return versions;","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/MrjarPlugin.java#L225-L261","documentation":"Thrown by MrjarPlugin.findSourceVersions when scanning the project's src/ directory for multi-release-jar source sets named mainNN (two-digit version) and finding one whose NN is less than the build's minimum compiler version (minJavaVersion). MRJAR versioned sources must target Java >= minJavaVersion so the versioned directory is a strict superset; a lower version duplicates the baseline without benefit and is rejected. A special exception: mainNN == minJavaVersion is allowed (the check is '<', not '<=') to permit incubating-module usage without preview warnings.","triggerScenarios":"findSourceVersions lists direct children of src/, matches each name against MRJAR_SOURCESET_PATTERN 'main(\\d{2})', parses the captured number, and throws if version < minJavaVersion. minJavaVersion is derived from buildParams.getMinimumCompilerVersion().getMajorVersion().","commonSituations":"Creating a src/main17 directory while the build's minimum compiler version is 21; reusing an old versioned source dir after a min-version bump (e.g. the build moved to JDK 21 but src/main11 still exists); naming a directory 'main09' or 'main11' inadvertently.","solutions":["Remove or rename the offending src/mainNN directory so NN >= minJavaVersion (the build's minimum compiler major version).","If the versioned sources are still relevant, bump NN to the current minJavaVersion (e.g. migrate src/main11 contents into src/main21 or into main).","If the directory is not an MRJAR source set, rename it so it does not match 'main(\\d{2})'.","After raising the build's minJavaVersion, sweep the tree for stale mainNN directories."],"exampleFix":"// before: build min compiler version is 21, but this dir exists\n//   src/main17/Foo.java\n// after: remove it, or move contents into src/main/ or src/main21/","handlingStrategy":"validation","validationCode":"import java.util.regex.Pattern;\nprivate static final Pattern MRJAR = Pattern.compile(\"main(\\\\d{2})\");\nint minJavaVersion = Integer.parseInt(\n    buildParams.getMinimumCompilerVersion().getMajorVersion());\nfor (Path p : Files.list(projectDir.toPath().resolve(\"src\")).toList()) {\n    var m = MRJAR.matcher(p.getFileName().toString());\n    if (m.matches() && Integer.parseInt(m.group(1)) < minJavaVersion) {\n        throw new IllegalStateException(\n            \"stale MRJAR source set \" + p + \" (< min java \" + minJavaVersion + \")\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After bumping the build's minimum compiler version, sweep src/ for stale mainNN directories and migrate them.","Remember mainNN == minJavaVersion is allowed (incubating-module workaround); only strictly lower versions fail.","Do not create mainNN directories casually; version only what genuinely needs version-specific sources."],"tags":["gradle","mrjar","multi-release-jar","java-version","build-config"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}