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

  1. List the directory: `ls -la $ES_HOME/lib/entitlement-bridge/`.
  2. If multiple jars, remove all and reinstall to leave exactly one.
  3. If zero jars, reinstall the distribution from a clean artifact.
  4. 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

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


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