testcontainers/testcontainers-java · error · IllegalStateException
Wait strategy failed. Container exited with code
Error message
Wait strategy failed. Container exited with code ${exitCode} What it means
Final fallback in tryStart's diagnostic chain: the wait strategy failed, Docker reports no error string, the container isn't dead/OOM-killed, and state.running is false — so the container simply exited. The message includes the container's exit code so you can map it to the application's own failure codes.
Solutions
- Read the container stdout/stderr logs printed right before this exception and correlate with the exit code.
- Fix the app-level startup failure (env vars, config files, ports) indicated in the logs.
- If the container is a one-off command, don't wait for a server — use execInContainer or a different lifecycle.
- Use a proper wait strategy matching the container's real readiness signal.
Example fix
// before
new GenericContainer<>("postgres:16"); // missing POSTGRES_PASSWORD -> exits 1
// after
new GenericContainer<>("postgres:16")
.withEnv("POSTGRES_PASSWORD", "test")
.waitingFor(Wait.forLogMessage(".*database system is ready to accept connections.*", 2)); Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
container.start();
} catch (ContainerLaunchException e) {
// cause message contains 'exited with code N' — map N to the app's failure codes
// container stdout/stderr is printed above the stack trace
throw e;
} Prevention
- Supply all env/config the app needs to boot (POSTGRES_PASSWORD, ports, config files).
- Read the printed container logs first — they almost always name the exact failure.
- Don't use one-off CLI images as long-running containers.
When it happens
Trigger: Container process exits on its own during startup — application-level failure (bad config, failed DB migration, port already in use inside the container), or the main process finishes quickly because it was run as a one-off command instead of a server.
Common situations: Postgres failing init due to bad POSTGRES_* env values; app crashing on missing required config; using a CLI-style image as a long-running container so it exits 0 immediately and the wait times out or detects exit.
Related errors
- Wait strategy failed. Container is removed
- Wait strategy failed. Container is dead
- Wait strategy failed. Container crashed
- You should never close the global DockerClient!
- Check failed:
AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12).
Data as JSON: /api/errors/1a5e5c9eda6d5232.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/testcontainers/containers/GenericContainer.java:519
InspectContainerResponse.ContainerState state = inspectContainerResponse.getState();
if (Boolean.TRUE.equals(state.getDead())) {
throw new IllegalStateException("Wait strategy failed. Container is dead", e);
}
if (Boolean.TRUE.equals(state.getOOMKilled())) {
throw new IllegalStateException(
"Wait strategy failed. Container crashed with out-of-memory (OOMKilled)",
e
);
}
String error = state.getError();
if (!StringUtils.isBlank(error)) {
throw new IllegalStateException("Wait strategy failed. Container crashed: " + error, e);
}
if (!Boolean.TRUE.equals(state.getRunning())) {
throw new IllegalStateException(
"Wait strategy failed. Container exited with code " + state.getExitCode(),
e
);
}
throw e;
}
logger().info("Container {} started in {}", dockerImageName, Duration.between(startedAt, Instant.now()));
containerIsStarted(containerInfo, reused);
} catch (Exception e) {
if (e instanceof UndeclaredThrowableException && e.getCause() instanceof Exception) {
e = (Exception) e.getCause();
}
if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) {
e = (Exception) e.getCause();
}
logger().error("Could not start container", e);View on GitHub (pinned to 8e549514e3)