testcontainers/testcontainers-java · error · java.lang.RuntimeException

Failed to detect protocol via curl

Error message

Failed to detect protocol via curl

What it means

ElasticsearchContainer.getHttpScheme() probes the running container by executing curl (HTTPS then HTTP) against localhost:9200 inside the container to determine which scheme the node is serving. This RuntimeException wraps any exception thrown while executing those probes (e.g. container exec failure). A sibling error reports probe results when both probes complete but fail.

Solutions

  1. Ensure the container image contains a curl binary (testcontainers images include it; custom images may not).
  2. Wait for the container to be running/ready (waitingFor(Wait.forHttp(...))) before calling getHttpScheme().
  3. Check the wrapped cause (RuntimeException.getCause()) for the actual exec failure and fix the underlying Docker/container issue.
  4. Upgrade the Elasticsearch container image to an official Testcontainers-supported one.

Example fix

// before
String scheme = container.getHttpScheme(); // may throw
// after
if (container.isRunning()) {
    String scheme = container.getHttpScheme();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!container.isRunning()) { throw new IllegalStateException("Container must be running before getHttpScheme()"); }

Try / catch

try { String scheme = container.getHttpScheme(); } catch (RuntimeException e) { LOG.error("curl protocol probe failed; check image has curl and container is alive", e.getCause()); throw e; }

Prevention

When it happens

Trigger: Calling getHttpScheme()/getHttpHostAddress()/url/scheme when execInContainer("curl", ...) throws — e.g. container stopped mid-probe, exec API failure, or curl missing from the image.

Common situations: Custom/minimal Elasticsearch images without curl installed; container stopped or paused by resource pressure between readiness checks and the probe; Docker engine issues during exec.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

            httpResult =
                execInContainer(
                    "curl",
                    "-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.

View on GitHub (pinned to 8e549514e3)