elastic/elasticsearch · critical · IllegalStateException

Directory for entitlement bridge jar does not exist: ${dir}

Error message

Directory for entitlement bridge jar does not exist: ${dir}

What it means

Thrown by SystemJvmOptions.attachEntitlementAgent when the `lib/entitlement-bridge` directory under ES_HOME does not exist. The entitlement bridge is a JVM agent jar that instruments JDK classes to enforce Elasticsearch's runtime entitlement policy; without it the node cannot enforce file/network/process entitlements. The error is an IllegalStateException because a shipped distribution should always contain this directory — its absence indicates a broken or tampered installation.

Source

Thrown at distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/SystemJvmOptions.java:164

        return enableNativeAccessOptions.stream();
    }

    /*
     * Only affects 22 and 22.0.1, see https://bugs.openjdk.org/browse/JDK-8329528
     */
    @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",

View on GitHub (pinned to db6a809a66)

Solutions

  1. Confirm ES_HOME points at a complete, freshly extracted distribution: `ls $ES_HOME/lib/entitlement-bridge/`.
  2. Re-extract or reinstall the distribution from an official artifact.
  3. If building from source, run the full distribution build (e.g. `./gradlew :distribution:archives:linux-tar:assemble`) and run from the assembled archive, not the source tree.
  4. Verify no startup script or Dockerfile is deleting lib/entitlement-bridge.

Example fix

# before
ES_HOME=/path/to/partial-extract
# after
ES_HOME=/path/to/full-elasticsearch-9.0.0
ls $ES_HOME/lib/entitlement-bridge  # should list exactly one jar
Defensive patterns

Strategy: validation

Validate before calling

Path bridge = esHome.resolve("lib/entitlement-bridge");
if (!Files.isDirectory(bridge)) {
    throw new IllegalStateException("Missing entitlement-bridge directory at " + bridge + "; reinstall the distribution.");
}

Type guard

static boolean hasEntitlementBridge(Path esHome) {
    return Files.isDirectory(esHome.resolve("lib/entitlement-bridge"));
}

Try / catch

try {
    List<String> opts = SystemJvmOptions.forEnv(env).getAsArguments();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("entitlement bridge")) {
        // halt deployment; alert ops that the distribution is incomplete
    } else throw e;
}

Prevention

When it happens

Trigger: Running Elasticsearch from a partial extraction of the distribution tarball/zip. A custom distribution that does not stage the entitlement-bridge jar. ES_HOME pointing at the wrong directory (e.g. the source tree rather than a built distribution). Deleting lib/entitlement-bridge manually.

Common situations: Operators copy only a subset of files when deploying. CI images built from a truncated `gradlew distribution:zip` output. Source-tree development where the dev runs `bin/elasticsearch` against an unbuilt layout.

Related errors


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