testcontainers/testcontainers-java · error · IllegalStateException

You should never close the global DockerClient!

Error message

You should never close the global DockerClient!

What it means

DockerClientFactory wraps the shared global DockerClient in a DockerClientDelegate whose close() throws this IllegalStateException. The client is a singleton shared across the JVM for all containers, so closing it would break every other consumer; the library deliberately forbids it.

Solutions

  1. Remove any close()/try-with-resources usage of the global DockerClient from DockerClientFactory.instance().client()
  2. If using a DI framework, register the client without a destroy/close method
  3. If you need a closable client, create your own DockerClient via DockerClientFactory or docker-java directly and close that one instead

Example fix

// before
try (DockerClient client = DockerClientFactory.instance().client()) {
    client.inspectContainerCmd(id).exec();
}
// after
DockerClient client = DockerClientFactory.instance().client();
client.inspectContainerCmd(id).exec(); // never close the global client
Defensive patterns

Strategy: try-catch

Validate before calling

if (client == DockerClientFactory.instance().client()) { throw new AssertionError("do not close the shared DockerClient"); }

Type guard

static boolean isSharedGlobalClient(DockerClient c) { return c instanceof DockerClientDelegate; }

Try / catch

try { client.close(); } catch (IllegalStateException e) { /* remove this close call entirely; never swallow into a retry */ }

Prevention

When it happens

Trigger: Calling close() on the DockerClient returned by DockerClientFactory.instance().client() (or any wrapper exposing the global client), e.g. in a finally block, try-with-resources, or a DI container disposing the client as a resource.

Common situations: Wrapping the client in try-with-resources by habit; shutting down a Spring/Guice context that registered the DockerClient as a Closeable bean; cleanup code that closes all Closeables in sight.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/testcontainers/DockerClientFactory.java:205

        if (cachedClientFailure != null) {
            log.debug("There is a cached checks failure - throwing", cachedClientFailure);
            throw cachedClientFailure;
        }

        if (client != null) {
            return client;
        }

        final DockerClientProviderStrategy strategy = getOrInitializeStrategy();

        client =
            new DockerClientDelegate() {
                @Getter
                final DockerClient dockerClient = strategy.getDockerClient();

                @Override
                public void close() {
                    throw new IllegalStateException("You should never close the global DockerClient!");
                }
            };
        log.info("Docker host IP address is {}", strategy.getDockerHostIpAddress());

        Info dockerInfo = strategy.getInfo();
        log.debug("Docker info: {}", dockerInfo.getRawValues());
        Version version = client.versionCmd().exec();
        log.debug("Docker version: {}", version.getRawValues());
        activeApiVersion = version.getApiVersion();

        String serverInfo =
            "Connected to docker: \n" +
            "  Server Version: " +
            dockerInfo.getServerVersion() +
            "\n" +
            "  API Version: " +
            activeApiVersion +
            "\n" +

View on GitHub (pinned to 8e549514e3)