elastic/elasticsearch · error · IllegalArgumentException

Not a valid module {} for {}

Error message

Not a valid module {} for {}

What it means

Thrown by installModules() when a module Provider<File> resolves to neither a .zip (case-insensitive) nor a directory. The node cannot install such an artifact into <distro>/modules and rejects it with IllegalArgumentException, signalling a configuration error in the module dependency.

Source

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

                }
            });
        }
    }

    private void installModules() {
        logToProcessStdout("Installing " + modules.size() + " modules");
        for (Provider<File> module : modules) {
            Path destination = getDistroDir().resolve("modules")
                .resolve(module.get().getName().replace(".zip", "").replace("-" + getVersion(), "").replace("-SNAPSHOT", ""));
            // only install modules that are not already bundled with the integ-test distribution
            if (Files.exists(destination) == false) {
                fileSystemOperations.copy(spec -> {
                    if (module.get().getName().toLowerCase().endsWith(".zip")) {
                        spec.from(archiveOperations.zipTree(module));
                    } else if (module.get().isDirectory()) {
                        spec.from(module);
                    } else {
                        throw new IllegalArgumentException("Not a valid module " + module + " for " + this);
                    }
                    spec.into(destination);
                });
            }
        }
    }

    @Override
    public void extraConfigFile(String destination, File from) {
        if (destination.contains("..")) {
            throw new IllegalArgumentException("extra config file destination can't be relative, was " + destination + " for " + this);
        }
        extraConfigFiles.put(destination, from);
    }

    @Override
    public void extraConfigFile(String destination, File from, PropertyNormalization normalization) {
        if (destination.contains("..")) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the offending module path printed in the message.
  2. Ensure the module dependency produces a .zip (or is a directory in dev runs): use the integ-test distribution zip of the module.
  3. Declare the dependency with the correct type, e.g. group:..., name:'my-module', version:..., type:'zip'.
  4. Invalidate the Gradle cache for that artifact (--refresh-dependencies) if you recently changed its type.

Example fix

// before: returns a jar/pom artifact
module(project(':my-module').configurations.archives)
// after: use the integ-test zip distribution of the module
module(project(':my-module').ext.distZip)
// or coordinate with explicit type
// dependencies { dists group:'org.elasticsearch.module', name:'my-module', version:'8.15.0', ext:'zip' }
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate every module provider yields a zip or directory before start
for (Provider<File> m : node.getModules()) {
    File f = m.get();
    String n = f.getName().toLowerCase();
    if (!n.endsWith(".zip") && !f.isDirectory()) {
        throw new IllegalStateException("Module artifact is neither zip nor dir: " + f);
    }
}

Type guard

// Only zip-producing or directory configurations are valid module inputs
static Provider<File> asModuleArtifact(TaskProvider<? extends Task> zipTask) {
    return zipTask.flatMap(t -> t.getOutputs().getFiles().getSingleFile().toPath().toFile());
}

Prevention

When it happens

Trigger: Calling module(provider) where the provider resolves to a pom, a tar, a .jar, or a missing/unrecognised artifact. Typically the wrong Gradle configuration or artifact type is wired up (e.g. a dependency declared with type 'pom' or 'tar' instead of 'zip').

Common situations: Maven coordinate for the module declared with the wrong type/classifier. Configuration returning the sources or pom artifact. Module project whose main output is a directory in dev mode but a zip in CI, with a configuration that returns neither. Stale artifact in cache after switching type.

Related errors


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