elastic/elasticsearch · critical · IllegalStateException
Expected one jar in ${dir}; found ${candidates.size()}
Error message
Expected one jar in ${dir}; found ${candidates.size()} What it means
Thrown by SystemJvmOptions.attachEntitlementAgent when the entitlement-bridge directory exists but does not contain exactly one jar. The code uses `Files.list(dir).limit(2).toList()` and requires size==1, so it fails for both zero jars and two-or-more jars. Multiple jars would create ambiguity about which agent to attach; zero jars means the build did not stage the artifact. Either case is treated as a corrupt installation.
Source
Thrown at distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/SystemJvmOptions.java:170
@UpdateForV10(owner = UpdateForV10.Owner.CORE_INFRA) // This could be removed when min JDK version = 25
private static Stream<String> maybeWorkaroundG1Bug() {
Runtime.Version v = Runtime.version();
if (v.feature() == 22 && v.update() <= 1) {
return Stream.of("-XX:+UnlockDiagnosticVMOptions", "-XX:G1NumCollectionsKeepPinned=10000000");
}
return Stream.of();
}
private static Stream<String> attachEntitlementAgent(Path esHome) {
Path dir = esHome.resolve("lib/entitlement-bridge");
if (Files.exists(dir) == false) {
throw new IllegalStateException("Directory for entitlement bridge jar does not exist: " + dir);
}
String bridgeJar;
try (var s = Files.list(dir)) {
var candidates = s.limit(2).toList();
if (candidates.size() != 1) {
throw new IllegalStateException("Expected one jar in " + dir + "; found " + candidates.size());
}
bridgeJar = candidates.get(0).toString();
} catch (IOException e) {
throw new IllegalStateException("Failed to list entitlement jars in: " + dir, e);
}
// We instrument classes in these modules to call the bridge. Because the bridge gets patched
// into java.base, we must export the bridge from java.base to these modules, as a comma-separated list
String modulesContainingEntitlementInstrumentation =
"java.logging,java.net.http,java.naming,jdk.net,jdk.zipfs,jdk.management.agent";
return Stream.of(
"-XX:+EnableDynamicAgentLoading",
"-Djdk.attach.allowAttachSelf=true",
"--patch-module=java.base=" + bridgeJar,
"--add-exports=java.base/org.elasticsearch.entitlement.bridge=org.elasticsearch.entitlement,"
+ modulesContainingEntitlementInstrumentation
);
}View on GitHub (pinned to db6a809a66)
Solutions
- List the directory: `ls -la $ES_HOME/lib/entitlement-bridge/`.
- If multiple jars, remove all and reinstall to leave exactly one.
- If zero jars, reinstall the distribution from a clean artifact.
- Adopt a deployment practice that extracts into a fresh directory per version rather than overlaying.
Example fix
# before $ ls $ES_HOME/lib/entitlement-bridge entitlement-bridge-9.0.0.jar entitlement-bridge-9.1.0.jar # after rm $ES_HOME/lib/entitlement-bridge/*.jar tar -xzf elasticsearch-9.1.0.tar.gz --strip-components=1 -C $ES_HOME lib/entitlement-bridge ls $ES_HOME/lib/entitlement-bridge # exactly one jar
Defensive patterns
Strategy: validation
Validate before calling
Path bridge = esHome.resolve("lib/entitlement-bridge");
try (var s = Files.list(bridge)) {
long count = s.count();
if (count != 1) {
throw new IllegalStateException("Expected exactly 1 entitlement-bridge jar, found " + count);
}
} Type guard
static boolean hasExactlyOneBridgeJar(Path esHome) throws IOException {
try (var s = Files.list(esHome.resolve("lib/entitlement-bridge"))) {
return s.count() == 1;
}
} Try / catch
try {
List<String> opts = SystemJvmOptions.forEnv(env).getAsArguments();
} catch (IllegalStateException e) {
if (e.getMessage().contains("Expected one jar")) {
// purge the directory and reinstall cleanly before retry
} else throw e;
} Prevention
- Deploy each version into its own directory; symlink to a current pointer rather than overwriting.
- Add a post-install assertion that `find lib/entitlement-bridge -name '*.jar' | wc -l` equals 1.
- Never manually swap jars without removing the previous version.
When it happens
Trigger: A previous upgrade left an old `entitlement-bridge-9.0.0.jar` next to a new `entitlement-bridge-9.1.0.jar`. An in-place extraction over an existing directory produced duplicates. A build that did not produce the bridge jar at all leaves the directory empty.
Common situations: Upgrading by unzipping a new distribution on top of the old one without cleaning lib/ first. Custom Docker layering that copies jars additively. Manual jar swaps that forget to remove the previous version.
Related errors
- Directory for entitlement bridge jar does not exist: ${dir}
- Failed to list entitlement jars in: ${dir}
- Missing procrun exe: ${procrun}
- CONFIG
- Ran out of versions to go to for {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/eb347b795848b29d.
Report an issue: GitHub.