{"record":{"id":"2bde776ef72d0d0b","repo":"junit-team/junit5","slug":"there-should-not-be-more-than-one-classpathscanner","errorCode":null,"errorMessage":"There should not be more than one ClasspathScanner implementation present on the classpath but there were %d: %s","messagePattern":"There should not be more than one ClasspathScanner implementation present on the classpath but there were (.+?): (.+?)","errorType":"exception","errorClass":"JUnitException","httpStatus":null,"severity":"error","filePath":"junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java","lineNumber":36,"sourceCode":"import org.junit.platform.commons.support.scanning.ClasspathScanner;\n\n/**\n * @since 1.12\n */\nclass ClasspathScannerLoader {\n\n\tstatic ClasspathScanner getInstance() {\n\t\tServiceLoader<ClasspathScanner> serviceLoader = ServiceLoader.load(ClasspathScanner.class,\n\t\t\tClassLoaderUtils.getDefaultClassLoader());\n\n\t\tList<Provider<ClasspathScanner>> classpathScanners = serviceLoader.stream().toList();\n\n\t\tif (classpathScanners.size() == 1) {\n\t\t\treturn classpathScanners.get(0).get();\n\t\t}\n\n\t\tif (classpathScanners.size() > 1) {\n\t\t\tthrow new JUnitException(\n\t\t\t\t\"There should not be more than one ClasspathScanner implementation present on the classpath but there were %d: %s\".formatted(\n\t\t\t\t\tclasspathScanners.size(),\n\t\t\t\t\tclasspathScanners.stream().map(Provider::type).map(Class::getName).toList()));\n\t\t}\n\n\t\treturn new DefaultClasspathScanner(ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass);\n\t}\n\n\tprivate ClasspathScannerLoader() {\n\t}\n\n}\n","sourceCodeStart":18,"sourceCodeEnd":49,"githubUrl":"https://github.com/junit-team/junit5/blob/f070c699a08b5d8393df9afd147af5c5e90bb21b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScannerLoader.java#L18-L49","documentation":"JUnitException thrown by ClasspathScannerLoader when java.util.ServiceLoader finds more than one ClasspathScanner implementation on the classpath. The SPI contract requires at most one provider; ambiguity is treated as a configuration error and the message lists both the count and the fully-qualified class names of all detected providers.","triggerScenarios":"Two or more JARs each register a META-INF/services/org.junit.platform.commons.support.scanning.ClasspathScanner entry and both are visible to the context ClassLoader used by ServiceLoader.load.","commonSituations":"Duplicate or conflicting junit-platform-commons JARs pulled in transitively plus shading; a third-party test library that ships its own ClasspathScanner alongside the default; fat-jar/uber-jar assembly merging multiple service entries.","solutions":["Inspect the error message - it lists the conflicting implementation class names","Run mvn dependency:tree or gradle dependencies to find duplicate providers","Exclude the duplicate junit-platform-commons artifact or the third-party scanner","Keep a single ClasspathScanner provider on the test runtime classpath"],"exampleFix":"// build.gradle.kts - force a single version\nconfigurations.all {\n  resolutionStrategy.eachDependency {\n    if (requested.group == \"org.junit.platform\") useVersion(\"1.13.3\")\n  }\n}","handlingStrategy":"validation","validationCode":"long count = ServiceLoader.load(ClasspathScanner.class).stream().count();\nif (count > 1) {\n    // fail fast with a clear build error before tests run\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run mvn dependency:tree or gradle dependencies before test runs to spot duplicate junit-platform-commons","Avoid shading test framework artifacts into uber-jars","Pin a single junit-bom version across the build"],"tags":["classpath","serviceloader","classpath-conflict","spi"],"backgroundTag":null,"analyzedSha":"f070c699a08b5d8393df9afd147af5c5e90bb21b","analyzedAt":"2026-08-11T20:31:00.530Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}