testcontainers/testcontainers-java · error · ContainerLaunchException
Local Docker Compose exited abnormally with code
Error message
Local Docker Compose exited abnormally with code ${exitValue} whilst running command: ${cmd} What it means
Thrown by LocalDockerCompose.invoke() as a ContainerLaunchException when the docker-compose process runs but exits with a non-zero status (InvalidExitValueException from the executeNoTimeout() call). The message includes the abnormal exit code and the full compose command, meaning the compose invocation itself failed (bad compose file, pull failure, build error, etc.).
Solutions
- Read the compose output in the test logs immediately above the exception — it contains the actual docker-compose error; fix that root cause.
- Run the same command locally (it is included in the message) in the working directory to reproduce and debug the failure.
- Verify the Docker daemon is running and the compose file is valid: `docker info` and `docker-compose -f <file> config`.
- Check image names/tags, registry credentials, and port bindings referenced by the compose file in the CI environment.
Example fix
// before: compose file references an image unavailable in CI
services:
db:
image: internal-registry/db:latest
// after: pin a pullable tag / add auth
services:
db:
image: internal-registry/db:1.4.2 Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the compose file before running the container
new ProcessBuilder("docker-compose", "-f", "docker-compose.yml", "config")
.inheritIO().start().waitFor(); // non-zero => invalid compose file Try / catch
try {
composeContainer.start();
} catch (ContainerLaunchException e) {
if (e.getMessage().contains("exited abnormally")) {
// message contains the compose command; rerun it for full diagnostics
throw new IllegalStateException("docker-compose failed: " + e.getMessage(), e);
}
throw e;
} Prevention
- Lint the compose file (`docker-compose config`) in CI before tests.
- Pin image tags and pre-pull them in CI to avoid registry flakiness.
- Ensure the Docker daemon is healthy before the test phase.
- Keep compose file version compatible with the installed binary.
When it happens
Trigger: DockerComposeContainer.start() driving LocalDockerCompose where `docker-compose up ...` executed in pwd returns a non-zero exitValue — e.g. invalid YAML, missing image, port conflicts, or build failures; caught from org.zeroturnaround.exec's InvalidExitValueException.
Common situations: Compose files referencing images that cannot be pulled (network/registry auth issues); services failing healthchecks so compose exits non-zero; compose file version incompatibilities between the installed binary and the file; Docker daemon not running at all (exit code 1).
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
- Containerised Docker Compose exited abnormally with code
- Local Docker Compose not found. Is
- You should never close the global DockerClient!
- Check failed:
- Services named do not exist, but wait conditions have been…
AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12).
Data as JSON: /api/errors/cc22a15c5796eed8.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/testcontainers/containers/LocalDockerCompose.java:117
final List<String> command = Splitter
.onPattern(" ")
.omitEmptyStrings()
.splitToList(this.composeExecutable + " " + cmd);
try {
new ProcessExecutor()
.command(command)
.redirectOutput(Slf4jStream.of(logger()).asInfo())
.redirectError(Slf4jStream.of(logger()).asInfo()) // docker-compose will log pull information to stderr
.environment(environment)
.directory(pwd)
.exitValueNormal()
.executeNoTimeout();
logger().info("Docker Compose has finished running");
} catch (InvalidExitValueException e) {
throw new ContainerLaunchException(
"Local Docker Compose exited abnormally with code " +
e.getExitValue() +
" whilst running command: " +
cmd
);
} catch (Exception e) {
throw new ContainerLaunchException("Error running local Docker Compose command: " + cmd, e);
}
}
/**
* @return a logger
*/
private Logger logger() {
return DockerLoggerFactory.getLogger(this.composeExecutable);
}
}
View on GitHub (pinned to 8e549514e3)