{"record":{"id":"eb347b795848b29d","repo":"elastic/elasticsearch","slug":"expected-one-jar-in-dir-found-candidates-siz","errorCode":null,"errorMessage":"Expected one jar in ${dir}; found ${candidates.size()}","messagePattern":"Expected one jar in (.+?); found (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/SystemJvmOptions.java","lineNumber":170,"sourceCode":"    @UpdateForV10(owner = UpdateForV10.Owner.CORE_INFRA) // This could be removed when min JDK version = 25\n    private static Stream<String> maybeWorkaroundG1Bug() {\n        Runtime.Version v = Runtime.version();\n        if (v.feature() == 22 && v.update() <= 1) {\n            return Stream.of(\"-XX:+UnlockDiagnosticVMOptions\", \"-XX:G1NumCollectionsKeepPinned=10000000\");\n        }\n        return Stream.of();\n    }\n\n    private static Stream<String> attachEntitlementAgent(Path esHome) {\n        Path dir = esHome.resolve(\"lib/entitlement-bridge\");\n        if (Files.exists(dir) == false) {\n            throw new IllegalStateException(\"Directory for entitlement bridge jar does not exist: \" + dir);\n        }\n        String bridgeJar;\n        try (var s = Files.list(dir)) {\n            var candidates = s.limit(2).toList();\n            if (candidates.size() != 1) {\n                throw new IllegalStateException(\"Expected one jar in \" + dir + \"; found \" + candidates.size());\n            }\n            bridgeJar = candidates.get(0).toString();\n        } catch (IOException e) {\n            throw new IllegalStateException(\"Failed to list entitlement jars in: \" + dir, e);\n        }\n\n        // We instrument classes in these modules to call the bridge. Because the bridge gets patched\n        // into java.base, we must export the bridge from java.base to these modules, as a comma-separated list\n        String modulesContainingEntitlementInstrumentation =\n            \"java.logging,java.net.http,java.naming,jdk.net,jdk.zipfs,jdk.management.agent\";\n        return Stream.of(\n            \"-XX:+EnableDynamicAgentLoading\",\n            \"-Djdk.attach.allowAttachSelf=true\",\n            \"--patch-module=java.base=\" + bridgeJar,\n            \"--add-exports=java.base/org.elasticsearch.entitlement.bridge=org.elasticsearch.entitlement,\"\n                + modulesContainingEntitlementInstrumentation\n        );\n    }","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/SystemJvmOptions.java#L152-L188","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n$ ls $ES_HOME/lib/entitlement-bridge\nentitlement-bridge-9.0.0.jar  entitlement-bridge-9.1.0.jar\n# after\nrm $ES_HOME/lib/entitlement-bridge/*.jar\ntar -xzf elasticsearch-9.1.0.tar.gz --strip-components=1 -C $ES_HOME lib/entitlement-bridge\nls $ES_HOME/lib/entitlement-bridge  # exactly one jar","handlingStrategy":"validation","validationCode":"Path bridge = esHome.resolve(\"lib/entitlement-bridge\");\ntry (var s = Files.list(bridge)) {\n    long count = s.count();\n    if (count != 1) {\n        throw new IllegalStateException(\"Expected exactly 1 entitlement-bridge jar, found \" + count);\n    }\n}","typeGuard":"static boolean hasExactlyOneBridgeJar(Path esHome) throws IOException {\n    try (var s = Files.list(esHome.resolve(\"lib/entitlement-bridge\"))) {\n        return s.count() == 1;\n    }\n}","tryCatchPattern":"try {\n    List<String> opts = SystemJvmOptions.forEnv(env).getAsArguments();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Expected one jar\")) {\n        // purge the directory and reinstall cleanly before retry\n    } else throw e;\n}","preventionTips":["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."],"tags":["cli","entitlements","jvm","installation","upgrade","agent"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}