testcontainers/testcontainers-java · error · RuntimeException

HTTP response code was

Error message

HTTP response code was: %s

What it means

HttpWaitStrategy polls a container's HTTP endpoint until it is ready. This RuntimeException is thrown when the server responds but the status code fails the configured statusCodePredicate (e.g. you asked for HTTP 200 but got 404/500). It usually means the endpoint is reachable but not behaving as expected yet.

Solutions

  1. Verify the actual status code with curl against the mapped port and fix the expected path/port in the wait strategy
  2. Allow the observed status codes via .forStatusCode(...) or .forStatusCodeMatching(...)
  3. Ensure livenessPort/https settings match the container's real listening port and protocol
  4. Increase .withStartupTimeout(...) if the code only transitions to 200 after longer warm-up

Example fix

// before
new HttpWaitStrategy().forPort(8080).forPath("/health").forStatusCode(200);
// after
new HttpWaitStrategy().forPort(8080).forPath("/actuator/health").forStatusCode(200).forStatusCode(503).withStartupTimeout(Duration.ofSeconds(60));
Defensive patterns

Strategy: validation

Validate before calling

// Verify the endpoint before waiting
String url = "http://" + container.getHost() + ":" + container.getMappedPort(8080) + "/health";
HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection();
int code = c.getResponseCode();
if (code != 200) throw new IllegalStateException("Endpoint returned " + code + ", adjust forStatusCode/forPath");

Try / catch

try {
    container.waitingFor(new HttpWaitStrategy().forStatusCode(200)).start();
} catch (ContainerLaunchException e) {
    if (e.getMessage().startsWith("HTTP response code was")) {
        // inspect container logs / adjust status predicate
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling HttpWaitStrategy.forStatusCode(200)/forStatusCodeMatching(predicate) (or default 200 requirement) while the container returns a different code, such as 404 for a wrong path or 503 while the app is still initializing.

Common situations: Wrong wait path/port configured; app returns 301/302 redirects instead of 200; endpoint returns 401 without auth headers; health endpoint briefly returns 503 during startup and the timeout window expires between polls.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java:295

                                // Choose the statusCodePredicate strategy depending on what we defined.
                                Predicate<Integer> predicate;
                                if (statusCodes.isEmpty() && statusCodePredicate == null) {
                                    // We have no status code and no predicate so we expect a 200 OK response code
                                    predicate = responseCode -> HttpURLConnection.HTTP_OK == responseCode;
                                } else if (!statusCodes.isEmpty() && statusCodePredicate == null) {
                                    // We use the default status predicate checker when we only have status codes
                                    predicate = responseCode -> statusCodes.contains(responseCode);
                                } else if (statusCodes.isEmpty()) {
                                    // We only have a predicate
                                    predicate = statusCodePredicate;
                                } else {
                                    // We have both predicate and status code
                                    predicate =
                                        statusCodePredicate.or(responseCode -> statusCodes.contains(responseCode));
                                }
                                if (!predicate.test(connection.getResponseCode())) {
                                    throw new RuntimeException(
                                        String.format("HTTP response code was: %s", connection.getResponseCode())
                                    );
                                }

                                if (responsePredicate != null) {
                                    String responseBody = getResponseBody(connection);

                                    log.trace("Get response {}", responseBody);

                                    if (!responsePredicate.test(responseBody)) {
                                        throw new RuntimeException(
                                            String.format("Response: %s did not match predicate", responseBody)
                                        );
                                    }
                                }
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }

View on GitHub (pinned to 8e549514e3)