elastic/elasticsearch · error · IllegalArgumentException

extra jar file {} doesn't appear to be a JAR

Error message

extra jar file {} doesn't appear to be a JAR

What it means

Thrown by copyExtraJars() when a File obtained from an extraJarFiles FileCollection does not end with '.jar'. The node copies extra jars into <distro>/lib and rejects anything that is not obviously a jar to avoid corrupting the classpath. The exception type is IllegalArgumentException (not TestClustersException), signalling a programming/configuration error rather than a runtime cluster fault.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:645

            }
        });
    }

    /**
     * Copies extra jars to the `/lib` directory.
     * //TODO: Remove this when system modules are available
     */
    private void copyExtraJars() {
        List<File> extraJarFiles = this.extraJarConfigurations.stream()
            .flatMap(fileCollection -> fileCollection.getFiles().stream())
            .toList();

        if (extraJarFiles.isEmpty() == false) {
            logToProcessStdout("Setting up " + this.extraJarConfigurations.size() + " additional jar dependencies");
        }
        extraJarFiles.forEach(from -> {
            if (from.getName().endsWith(".jar") == false) {
                throw new IllegalArgumentException("extra jar file " + from + " doesn't appear to be a JAR");
            }

            Path destination = getDistroDir().resolve("lib").resolve(from.getName());
            try {
                Files.copy(from.toPath(), destination, StandardCopyOption.REPLACE_EXISTING);
                LOGGER.info("Added extra jar {} to {}", from.getName(), destination);
            } catch (IOException e) {
                throw new UncheckedIOException("Can't copy extra jar dependency " + from.getName() + " to " + destination, e);
            }
        });
    }

    private void configureSecurity() {
        if (credentials.isEmpty() == false) {
            logToProcessStdout("Setting up " + credentials.size() + " users");

            credentials.forEach(
                paramMap -> runElasticsearchBinScript(

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the offending path printed in the message and confirm it should be a jar.
  2. Use the correct configuration: a runtime classpath whose artifacts end with .jar (e.g. project.configurations.runtimeClasspath filtered to .jar).
  3. If you genuinely need a non-jar on the classpath, package it as a jar first.
  4. Filter the FileCollection before passing: configurations.myConfig.filter { it.name.endsWith('.jar') }.

Example fix

// before: passes a configuration that contains pom/sources
extraJarFiles(configurations.implementation)
// after: filter to jars only
extraJarFiles(configurations.implementation.filter { it.name.endsWith('.jar') })
Defensive patterns

Strategy: type-guard

Validate before calling

// Filter any FileCollection to jars before registering
FileCollection jars = myConfig.filter(f -> f.getName().toLowerCase().endsWith(".jar"));
node.extraJarFiles(jars);

Type guard

// Type guard: only jars are valid inputs to extraJarFiles
static FileCollection onlyJars(FileCollection in) {
    return in.filter(f -> f.getName().toLowerCase().endsWith(".jar"));
}

Prevention

When it happens

Trigger: Calling extraJarFiles(from) with a FileCollection that resolves to a non-jar artifact: a pom, sources jar classifier stripped by mistake, a directory, a zip, or a plain class file. Often happens when a configuration is mistyped (e.g. using 'runtimeClasspath' or 'sources' instead of 'runtimeElements').

Common situations: Mistakenly passing a sources/javadoc configuration. A third-party dependency whose artifact lacks the .jar extension. A test fixture that bundles classes in a directory. Shadow/fat-jar task output named without .jar.

Related errors


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