testcontainers/testcontainers-java · error · RuntimeException
Response: did not match predicate
Error message
Response: %s did not match predicate
What it means
HttpWaitStrategy supports an optional body-level predicate set with withResponsePredicate. When the HTTP status passes but the response body fails that predicate, this RuntimeException is thrown so the strategy keeps retrying until timeout. It means the endpoint answered correctly at the HTTP level but its content is not what you declared as 'ready'.
Solutions
- Log the actual body (it is printed in the message) and adjust the predicate to match reality
- Parse structured bodies (e.g. with Jackson) instead of raw string matching
- Make the predicate tolerant of intermediate states (e.g. accept both 'starting' and 'ready')
- Combine with .forStatusCode(200) so obvious errors fail on status first
Example fix
// before
.withResponsePredicate(body -> body.equals("OK"))
// after
.withResponsePredicate(body -> body.contains("\"status\":\"UP\"")) Defensive patterns
Strategy: validation
Validate before calling
// Assert the expected body shape against a live response before configuring the predicate
String body = new HttpWaitStrategy().getResponseBody(
(HttpURLConnection) new URL(baseUrl + "/health").openConnection());
if (!body.contains("\"status\":\"UP\"")) {
throw new IllegalStateException("Unexpected body: " + body);
} Try / catch
try {
container.waitingFor(new HttpWaitStrategy().withResponsePredicate(this::isValidHealthBody)).start();
} catch (ContainerLaunchException e) {
if (e.getMessage().contains("did not match predicate")) {
// log real body from the message and refine the predicate
}
throw e;
} Prevention
- Write predicates against parsed JSON, not raw string equality
- Keep the predicate tolerant of intermediate app states
- Version-check the app's health payload format when upgrading the app under test
When it happens
Trigger: Calling HttpWaitStrategy.withResponsePredicate(body -> body.contains("OK")) while the actual response body differs (empty body, JSON error payload, HTML error page).
Common situations: Predicate written against a response format that changed between app versions; JSON body compared with plain-string contains instead of parsing; charset/encoding mismatch making the body look different.
Related errors
- HTTP response code was
- Timed out waiting for URL to be accessible
- you cannot specify a value smaller than 1 ms
- Unable to create custom SSL factory instance
- Timed out waiting for log output matching
AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12).
Data as JSON: /api/errors/7e2b6bd7359d1842.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/testcontainers/containers/wait/strategy/HttpWaitStrategy.java:306
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);
}
});
return true;
}
);
} catch (TimeoutException e) {
throw new ContainerLaunchException(
String.format(
"Timed out waiting for URL to be accessible (%s should return HTTP %s)",
uri,
statusCodes.isEmpty() ? HttpURLConnection.HTTP_OK : statusCodes
),View on GitHub (pinned to 8e549514e3)