elastic/elasticsearch · error · IllegalArgumentException

unrecognized classpath entry

Error message

unrecognized classpath entry: {}

What it means

Thrown by GenerateTestBuildInfoTask.buildLocationList when a classpath code-location entry that exists on disk is neither a .jar file (matching JAR_DESCRIPTOR_SUFFIX) nor a directory. The task only knows how to scan jars and directories for test location metadata, so any other file shape is rejected.

Solutions

  1. Inspect the offending file path printed in the message — confirm it is unexpected, then fix the configuration feeding getCodeLocations().
  2. Ensure all code-location entries are either compiled output directories (classes dirs) or .jar artifacts.
  3. Run with --rerun-tasks and clean to drop stale cache entries that may have produced a non-jar file.
  4. If you must point at an archive, package it as a .jar so the JAR_DESCRIPTOR_SUFFIX branch handles it.

Example fix

// before
testBuildInfo {
  codeLocations.from files('build/libs/app.zip')  // not a jar, not a dir
}

// after
testBuildInfo {
  codeLocations.from sourceSets.main.output, configurations.runtimeClasspath
}
Defensive patterns

Strategy: validation

Validate before calling

for (File f : codeLocationFiles) {
    if (!f.exists()) continue;
    if (!f.getName().endsWith(".jar") && !f.isDirectory()) {
        throw new IllegalArgumentException("Refusing to add non-jar non-dir classpath entry: " + f);
    }
}

Prevention

When it happens

Trigger: getCodeLocations().get().getFiles() returns a File that exists, does not end in .jar, and is not a directory (e.g. a .class file, a .zip, a broken symlink resolved to a non-jar file, a flat file passed as a code location).

Common situations: Misconfiguring a test task's classpath to point at a loose file or a non-jar archive; a stale build cache returning a placeholder file; symlinks in the build dir resolving to odd targets.

Related errors


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

Appendix: source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java:133

     *                            whose name will be unique within its {@link ClassLoader} at run time.
     */
    record Location(String module, String representativeClass) {}

    /**
     * Build the list of {@link Location}s for all {@link #getCodeLocations() code locations}.
     * There are different methods for finding these depending on if the
     * classpath entry is a jar or a directory
     */
    private List<Location> buildLocationList() throws IOException {
        List<Location> locations = new ArrayList<>();
        for (File file : getCodeLocations().get().getFiles()) {
            if (file.exists()) {
                if (file.getName().endsWith(JAR_DESCRIPTOR_SUFFIX)) {
                    extractLocationsFromJar(file, locations);
                } else if (file.isDirectory()) {
                    extractLocationsFromDirectory(file, locations);
                } else {
                    throw new IllegalArgumentException("unrecognized classpath entry: " + file);
                }
            }
        }
        return List.copyOf(locations);
    }

    /**
     * find the first class and module when the class path entry is a jar
     */
    private void extractLocationsFromJar(File file, List<Location> locations) throws IOException {
        try (JarFile jarFile = new JarFile(file)) {
            var className = extractClassNameFromJar(jarFile);

            if (className.isPresent()) {
                String moduleName = extractModuleNameFromJar(file, jarFile);
                locations.add(new Location(moduleName, className.get()));
            }
        }

View on GitHub (pinned to db6a809a66)