testcontainers/testcontainers-java · error · RuntimeException

Failed to detect protocol via curl. Both HTTPS and HTTP…

Error message

Failed to detect protocol via curl. Both HTTPS and HTTP probes failed. HTTPS probe - exit code: %d, stdout: %s, stderr: %s; HTTP probe - exit code: %d, stdout: %s, stderr: %s

What it means

getHttpScheme() runs two curl probes inside the Elasticsearch container (HTTPS with -k, then HTTP) against localhost:9200 and reads the HTTP status code. If neither probe yields an HTTP response (exit code 0 and http_code != '000'), it throws this RuntimeException containing both probes' exit codes, stdout and stderr for diagnosis.

Solutions

  1. Inspect the container logs (container.getLogs()) to see why Elasticsearch is not responding.
  2. Increase/fix the wait strategy (Wait.forHttp("/") with enough startup timeout) so getHttpScheme is only called when ES is ready.
  3. Check host settings: vm.max_map_count >= 262144 and sufficient memory for the container.
  4. Read the HTTPS/HTTP probe details in the message: exit code and stderr indicate whether TLS handshake or connection itself failed.
  5. Use default images (docker.elastic.co/elasticsearch/elasticsearch) where security/scheme behavior matches what getHttpScheme expects.

Example fix

// before
elasticsearch.start();
String url = elasticsearch.getHttpHostAddress(); // throws if ES not ready
// after
elasticsearch.withStartupTimeout(Duration.ofMinutes(3))
    .waitingFor(Wait.forHttp("/").forStatusCodeAllowingRedirects());
elasticsearch.start();
String url = elasticsearch.getHttpHostAddress();
Defensive patterns

Strategy: retry

Validate before calling

if (!container.isRunning()) { throw new IllegalStateException("Elasticsearch container not running"); }

Try / catch

try { String addr = es.getHttpHostAddress(); } catch (RuntimeException e) { System.err.println(es.getLogs()); throw e; }

Prevention

When it happens

Trigger: Calling getHttpScheme()/url/scheme/getHttpHostAddress after the container reports running, but Elasticsearch is not accepting connections on port 9200 yet (still starting, crashed, OOM-killed, or bound to a different port).

Common situations: Elasticsearch taking longer than the wait strategy allows to start; vm.max_map_count too low causing ES startup failure; memory limits killing the ES process; wrong security-enabled setting so the probe misses the actual listener.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12). Data as JSON: /api/errors/35749e0e95dccb2a. Report an issue: GitHub.

Appendix: source

Thrown at modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java:342

                    "-sS",
                    "--connect-timeout",
                    "2",
                    "--max-time",
                    "4",
                    "-o",
                    "/dev/null",
                    "-w",
                    "%{http_code}",
                    "http://localhost:" + ELASTICSEARCH_DEFAULT_PORT + "/"
                );
            if (httpResult.getExitCode() == 0 && !"000".equals(httpResult.getStdout().trim())) {
                return "http";
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to detect protocol via curl", e);
        }

        throw new RuntimeException(
            String.format(
                "Failed to detect protocol via curl. Both HTTPS and HTTP probes failed. " +
                "HTTPS probe - exit code: %d, stdout: %s, stderr: %s; " +
                "HTTP probe - exit code: %d, stdout: %s, stderr: %s",
                httpsResult.getExitCode(),
                httpsResult.getStdout(),
                httpsResult.getStderr(),
                httpResult.getExitCode(),
                httpResult.getStdout(),
                httpResult.getStderr()
            )
        );
    }

    // The TransportClient will be removed in Elasticsearch 8. No need to expose this port anymore in the future.
    @Deprecated
    public InetSocketAddress getTcpHost() {
        return new InetSocketAddress(getHost(), getMappedPort(ELASTICSEARCH_DEFAULT_TCP_PORT));

View on GitHub (pinned to 8e549514e3)