testcontainers/testcontainers-java · critical · ContainerLaunchException

Container startup failed for image

Error message

Container startup failed for image ${dockerImageName}

What it means

GenericContainer.doStart wraps any exception raised while creating/starting the container in a ContainerLaunchException with this message, using the Docker image name for context. It is a wrapper: the root cause (nested exception) holds the actual failure — image pull failure, port conflict, startup check failure, wait strategy timeout, etc.

Solutions

  1. Read the 'Caused by' chain of this ContainerLaunchException to find the root cause.
  2. Verify the image name/tag is correct and pullable (docker pull <image>).
  3. Check the Docker daemon is up and reachable (docker info).
  4. Increase the wait strategy timeout if the container starts slowly: container.waitingFor(Wait.forLogMessage(...)).withStartupTimeout(Duration.ofMinutes(2)).
  5. Inspect container stdout/stderr logs printed by Testcontainers just before this exception for the real startup error.

Example fix

// before
try {
    container.start();
} catch (ContainerLaunchException ignored) { }
// after
try {
    container.start();
} catch (ContainerLaunchException e) {
    // log the full cause chain to see the real startup failure
    logger.error("Container startup failed", e);
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean dockerUp = java.util.Optional.ofNullable(
    new ProcessBuilder("docker", "info").start().waitFor() == 0).orElse(false);

Type guard

null

Try / catch

try {
    container.start();
} catch (ContainerLaunchException e) {
    // root cause is in the cause chain — log it fully before retrying or failing
    logger.error("Startup failed for {}", container.getDockerImageName(), e);
    throw e;
}

Prevention

When it happens

Trigger: Any failure inside container.start() → doStart(): image not found/unpullable, Ryuk or Docker unavailable, startup check failing (container never reaches running state), wait strategy timeout, reuse validation failing, or InspectContainerResponse problems during tryStart.

Common situations: Typo in image name/tag so the pull fails; Docker daemon not running; private registry requiring credentials; container crashes immediately so the wait strategy times out; insufficient resources (OOM) killing the container during startup.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/testcontainers/containers/GenericContainer.java:346

            logger().debug("Starting container: {}", getDockerImageName());

            AtomicInteger attempt = new AtomicInteger(0);
            Unreliables.retryUntilSuccess(
                startupAttempts,
                () -> {
                    logger()
                        .debug(
                            "Trying to start container: {} (attempt {}/{})",
                            getDockerImageName(),
                            attempt.incrementAndGet(),
                            startupAttempts
                        );
                    tryStart();
                    return true;
                }
            );
        } catch (Exception e) {
            throw new ContainerLaunchException("Container startup failed for image " + getDockerImageName(), e);
        }
    }

    @UnstableAPI
    @SneakyThrows
    protected boolean canBeReused() {
        for (Class<?> type = getClass(); type != GenericContainer.class; type = type.getSuperclass()) {
            try {
                Method method = type.getDeclaredMethod("containerIsCreated", String.class);
                if (method.getDeclaringClass() != GenericContainer.class) {
                    logger().warn("{} can't be reused because it overrides {}", getClass(), method.getName());
                    return false;
                }
            } catch (NoSuchMethodException | NoClassDefFoundError e) {
                // ignore
            }
        }

View on GitHub (pinned to 8e549514e3)