elastic/elasticsearch · error · RuntimeException

Failed to load class {name}. Incorrect classpath?

Error message

Failed to load class {name}. Incorrect classpath?

What it means

Thrown by TestingConventionsCheckTask.loadClassWithoutInitializing when Class.forName(name, false, classLoader) raises ClassNotFoundException. The visitor collected a .class file's fully-qualified name but the configured classloader cannot resolve that class, indicating the classpath feeding the check is incomplete or inconsistent with the compiled output being scanned.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/TestingConventionsCheckTask.java:261

                && Modifier.isStatic(method.getModifiers()) == false
                && method.getReturnType().equals(Void.TYPE);
        }

        private static boolean isAnnotated(Method method, Class<?> annotation) {
            return Stream.of(method.getAnnotations())
                .anyMatch(presentAnnotation -> annotation.isAssignableFrom(presentAnnotation.getClass()));
        }

        private static Class<?> loadClassWithoutInitializing(String name, ClassLoader classLoader) {
            try {
                return Class.forName(
                    name,
                    // Don't initialize the class to save time. Not needed for this test and this doesn't share a VM with any other tests.
                    false,
                    classLoader
                );
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("Failed to load class " + name + ". Incorrect classpath?", e);
            }
        }
    }

    private static final class ClassLoadingFileVisitor extends EmptyFileVisitor {
        private static final String CLASS_POSTFIX = ".class";
        private List<String> fullQualifiedClassNames = new ArrayList<>();

        @Override
        public void visitFile(FileVisitDetails fileVisitDetails) {
            String fileName = fileVisitDetails.getName();
            if (fileName.endsWith(CLASS_POSTFIX)) {
                String packageName = Arrays.stream(fileVisitDetails.getRelativePath().getSegments())
                    .takeWhile(s -> s.equals(fileName) == false)
                    .collect(Collectors.joining("."));
                String simpleClassName = fileName.replace(CLASS_POSTFIX, "");
                String fullQualifiedClassName = packageName + (packageName.isEmpty() ? "" : ".") + simpleClassName;
                fullQualifiedClassNames.add(fullQualifiedClassName);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Confirm the task's classloader classpath includes the compiled class roots being scanned (project.output + test dependencies).
  2. Clean and rebuild the affected project (./gradlew :<project>:clean :<project>:compileTestJava) to remove stale .class files.
  3. If a referenced class was deleted from source but a stale .class remains, a clean removes it; if it's a legitimate external class, add the missing dependency.
  4. Re-run :<project>:testingConventions with --info to see the failing class name, then verify it exists in source.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure scanned class roots are on the classloader's classpath
List<File> roots = compiledOutputRoots;
URLClassLoader cl = new URLClassLoader(toUrls(roots), parent);
for (String fqcn : visitor.fullQualifiedClassNames) {
    if (cl.getResource(fqcn.replace('.', '/') + ".class") == null) {
        throw new IllegalStateException("Scanned class not on classpath: " + fqcn);
    }
}

Try / catch

try { Class<?> c = loadClassWithoutInitializing(name, cl); }
catch (RuntimeException e) {
    if (e.getCause() instanceof ClassNotFoundException) { /* fix classpath, do not ignore */ }
    throw e;
}

Prevention

When it happens

Trigger: The ClassLoadingFileVisitor enumerates .class files under compiled output and the task then attempts Class.forName for each; if the classloader was built from a classpath that omits the directory actually being scanned (or a parent/sibling output it depends on), ClassNotFoundException is raised.

Common situations: The convention check's classpath does not include the project's own compiled output dir; incremental/parallel build produced a stale class file whose source was removed; cross-project test fixtures referenced but not on the classpath; misconfigured custom SourceSet whose output isn't wired into the check.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/8752a6291aa38778. Report an issue: GitHub.