{"record":{"id":"f79712df07337c4e","repo":"testcontainers/testcontainers-java","slug":"ca-cert-under-not-found","errorCode":null,"errorMessage":"CA cert under  not found.","messagePattern":"CA cert under  not found\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java","lineNumber":151,"sourceCode":"    /**\n     * If this is running above Elasticsearch 8, this will return the probably self-signed CA cert that has been extracted\n     *\n     * @return byte array optional containing the CA cert extracted from the docker container\n     */\n    public Optional<byte[]> caCertAsBytes() {\n        if (StringUtils.isBlank(certPath)) {\n            return Optional.empty();\n        }\n        try {\n            byte[] bytes = copyFileFromContainer(certPath, IOUtils::toByteArray);\n            if (bytes.length > 0) {\n                return Optional.of(bytes);\n            }\n        } catch (NotFoundException e) {\n            // just emit an error message, but do not throw an exception\n            // this might be ok, if the docker image is accidentally looking like version 8 or latest\n            // can happen if Elasticsearch is repackaged, i.e. with custom plugins\n            log.warn(\"CA cert under \" + certPath + \" not found.\");\n        }\n        return Optional.empty();\n    }\n\n    /**\n     * A SSL context based on the self-signed CA, so that using this SSL Context allows to connect to the Elasticsearch service\n     * @return a customized SSL Context\n     */\n    public SSLContext createSslContextFromCa() {\n        try {\n            CertificateFactory factory = CertificateFactory.getInstance(\"X.509\");\n            Certificate trustedCa = factory.generateCertificate(\n                new ByteArrayInputStream(\n                    caCertAsBytes()\n                        .orElseThrow(() -> new IllegalStateException(\"CA cert under \" + certPath + \" not found.\"))\n                )\n            );\n            KeyStore trustStore = KeyStore.getInstance(\"pkcs12\");","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/testcontainers/testcontainers-java/blob/8e549514e3f01c57d70546fbb8599d138f3903e5/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java#L133-L169","documentation":"ElasticsearchContainer.caCertAsBytes copies the self-signed CA certificate (http_ca.crt) out of a v8-style Elasticsearch container. If the cert file is not present (NotFoundException from exec, e.g. because the image is actually v7 or a repackaged variant), it logs this warning and returns Optional.empty(). Callers like getClient/protocol then fall back to plain HTTP. The warning is intentional and non-fatal.","triggerScenarios":"The container image looks like Elasticsearch 8 (or uses the v8 default config path) so SSL setup is attempted, but /usr/share/elasticsearch/config/certs/http_ca.crt does not exist inside the container — typically a v7 image or a custom/repackaged image that resembles v8.","commonSituations":"Using elasticsearch:latest and getting a v7 image; custom Elasticsearch builds with plugins where the cert path differs; image tags like 8.0.0 but with security disabled in custom config so no cert is generated.","solutions":["Pin an explicit version tag matching your intended major version (e.g. 7.17.9 or 8.11.0) instead of latest","If using a v7 image, don't rely on the SSL client: use getHttpHostAddress and plain HTTP clients","For custom images, ensure the CA cert exists at /usr/share/elasticsearch/config/certs/http_ca.crt or override withEnv security settings consistently","Treat the Optional.empty() return: guard client code to handle absent CA (fallback to non-SSL)"],"exampleFix":"// before\nElasticsearchContainer es = new ElasticsearchContainer(\"elasticsearch:latest\");\nString caCertAsBase64 = Base64.getEncoder().encodeToString(es.caCertAsBytes()); // may NPE\n// after\nes.caCertAsBytes().ifPresentOrElse(\n    cert -> connectWithSsl(cert),\n    () -> connectPlainHttp(es.getHttpHostAddress())\n);","handlingStrategy":"fallback","validationCode":"// decide SSL vs plain from the Optional before building clients\nOptional<byte[]> ca = container.caCertAsBytes();\nboolean useSsl = ca.isPresent();","typeGuard":null,"tryCatchPattern":"try {\n    byte[] cert = container.caCertAsBytes().orElseThrow(() -> new IllegalStateException(\"No CA cert; image is not v8-style\"));\n    connectWithSsl(cert);\n} catch (IllegalStateException e) {\n    connectPlainHttp(container.getHttpHostAddress());\n}","preventionTips":["Pin explicit Elasticsearch version tags so v7/v8 behavior is predictable","Never assume caCertAsBytes() returns a value — it returns Optional.empty() for v7-style images","For custom/repackaged images, ensure http_ca.crt exists at the expected path or disable SSL expectations","Build client setup that branches on the Optional instead of blindly using the SSL client"],"tags":["elasticsearch","ssl","certificate","versioning"],"backgroundTag":"resource-not-found","analyzedSha":"8e549514e3f01c57d70546fbb8599d138f3903e5","analyzedAt":"2026-09-12T14:56:41.227Z","contentChangedAt":"2026-09-12T14:56:41.227Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}