elastic/elasticsearch · error · IllegalArgumentException
unexpected jar name: {jarName}
Error message
unexpected jar name: {jarName} What it means
Thrown as an IllegalArgumentException by EmbeddedModulePath.version when the supplied jar file name does not end with '.jar'. version() derives an automatic module's version from the jar filename per the JDK ModuleFinder contract; a non-jar name breaks the parsing precondition. Because the method is called with path.getFileName() during automatic-module descriptor building, this typically means a misnamed embedded artifact.
Source
Thrown at libs/core/src/main/java/org/elasticsearch/core/internal/provider/EmbeddedModulePath.java:160
// Scans a given path for class files and services.
static ScanResult scan(Path path) throws IOException {
try (var stream = Files.walk(path)) {
Map<Boolean, Set<String>> map = stream.filter(p -> Files.isDirectory(p) == false)
.map(p -> path.relativize(p).toString())
.filter(p -> (p.endsWith(".class") ^ p.startsWith(SERVICES_PREFIX)))
.collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), Collectors.toSet()));
return new ScanResult(map.get(Boolean.FALSE), map.get(Boolean.TRUE));
}
}
private static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
// Determines the module version (of an automatic module), given the jar file name. As per,
// https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/lang/module/ModuleFinder.html#of(java.nio.file.Path...)
static Optional<ModuleDescriptor.Version> version(String jarName) {
if (jarName.endsWith(".jar") == false) {
throw new IllegalArgumentException("unexpected jar name: " + jarName);
}
// drop ".jar"
String name = jarName.substring(0, jarName.length() - 4);
// find first occurrence of -${NUMBER}. or -${NUMBER}$
Matcher matcher = DASH_VERSION.matcher(name);
if (matcher.find()) {
int start = matcher.start();
try {
String tail = name.substring(start + 1);
return Optional.of(ModuleDescriptor.Version.parse(tail));
} catch (IllegalArgumentException ignore) {}
}
return Optional.empty();
}
// Parses a set of given service files, and returns a map of service name to list of provider
// classes.
static Map<String, List<String>> services(Set<String> serviceFiles, Path path) throws IOException {View on GitHub (pinned to db6a809a66)
Solutions
- Ensure embedded provider artifacts are real .jar files named with the .jar extension.
- Check the jar listing resource (the file under IMPL-JARS/<provider>/) — each entry must end in .jar.
- If the artifact is an exploded directory, do not route its filename through version(); only jar filenames are valid.
- Rebuild/repackage the artifact as a jar.
Defensive patterns
Strategy: validation
Validate before calling
// Require .jar extension before deriving a version from a filename
static Optional<Version> safeVersion(String jarName) {
if (jarName == null || !jarName.endsWith(".jar")) {
throw new IllegalArgumentException("unexpected jar name: " + jarName);
}
return EmbeddedModulePath.version(jarName);
} Type guard
static boolean looksLikeJarName(String name) {
return name != null && name.endsWith(".jar");
} Try / catch
try {
return EmbeddedModulePath.version(fileName);
} catch (IllegalArgumentException e) {
// the artifact is not a jar; repackage or skip version derivation
return Optional.empty();
} Prevention
- Name embedded provider archives with the .jar extension only.
- Keep the IMPL-JARS listing entries ending in .jar.
- Do not pass directory names or zip files to version().
- Validate filenames before automatic-module descriptor building.
When it happens
Trigger: Calling EmbeddedModulePath.version(name) with a name like 'xlib-2.10.4', 'classes', 'lib.zip', or any string not ending in '.jar'. Indirectly triggered during descriptorForAutomatic when an embedded provider archive is named without the .jar extension.
Common situations: A build/copied artifact that lost its .jar extension (e.g. renamed during shading, or an exploded directory name passed where a jar name was expected). A test passing a path's filename that is a directory. A packaging step that bundles classes without producing a jar.
Related errors
- automatic module without a manifest name is not supported, f
- Automatic-Module-Name: {e.getMessage()}
- {name} found in top-level directory (unnamed package not all
- unknown scheme:{rootURI.getScheme()}
- missing %s provider jars list
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/a10e5645c5edbd4b.
Report an issue: GitHub.