testcontainers/testcontainers-java · error · IllegalStateException

execInContainer can only be used while the Container is…

Error message

execInContainer can only be used while the Container is running

What it means

Testcontainers throws this IllegalStateException from ExecInContainerPattern.execInContainer when you attempt to run a command inside a container that is not in the running state. Docker's exec API only works against a live container, so the library validates the container state (via the cached InspectContainerResponse) before calling it and fails fast with a clear message instead of an obscure Docker API error.

Solutions

  1. Ensure container.start() has completed before calling execInContainer (e.g. move the exec into the test method or after startup callbacks).
  2. Do not call stop() on the container before the exec; check lifecycle ordering in @BeforeAll/@AfterAll.
  3. Guard the call with container.isRunning() and skip or start the container as needed.
  4. If the container is exiting on its own, fix the container's command/entrypoint so it stays alive (e.g. keep the main process in the foreground).

Example fix

// before
container.execInContainer("sh", "-c", "load-data.sh"); // may run before start
// after
container.start();
if (container.isRunning()) {
    container.execInContainer("sh", "-c", "load-data.sh");
}
Defensive patterns

Strategy: validation

Validate before calling

if (!container.isRunning()) {
    container.start();
}
container.execInContainer("sh", "-c", "setup.sh");

Type guard

boolean canExec(GenericContainer<?> c) { return c.isRunning(); }

Try / catch

try {
    container.execInContainer("cmd");
} catch (IllegalStateException e) {
    if (e.getMessage().contains("only be used while the Container is running")) {
        container.start();
        container.execInContainer("cmd");
    } else throw e;
}

Prevention

When it happens

Trigger: Calling container.execInContainer("cmd") (or execInContainer(WaitStrategies variant) with a charset/timeout) before container.start() has completed, after container.stop() has been called, or from a different thread while the container is concurrently being stopped; also when the container already exited/crashed but the test still tries to exec into it.

Common situations: Tests that exec a setup command in @BeforeAll before the container is started; using execInContainer in @AfterAll after stop(); JUnit reusing a container across tests where a previous test stopped it; containers whose process exited early (e.g. bad entrypoint) so isRunning() is false by the time the exec runs.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/testcontainers/containers/ExecInContainerPattern.java:196

     * @throws IOException if there's an issue communicating with Docker
     * @throws InterruptedException if the thread waiting for the response is interrupted
     * @throws UnsupportedOperationException if the docker daemon you're connecting to doesn't support "exec".
     */
    public Container.ExecResult execInContainer(
        DockerClient dockerClient,
        InspectContainerResponse containerInfo,
        Charset outputCharset,
        ExecConfig execConfig
    ) throws UnsupportedOperationException, IOException, InterruptedException {
        if (!TestEnvironment.dockerExecutionDriverSupportsExec()) {
            // at time of writing, this is the expected result in CircleCI.
            throw new UnsupportedOperationException(
                "Your docker daemon is running the \"lxc\" driver, which doesn't support \"docker exec\"."
            );
        }

        if (!isRunning(containerInfo)) {
            throw new IllegalStateException("execInContainer can only be used while the Container is running");
        }

        String containerId = containerInfo.getId();
        String containerName = containerInfo.getName();

        String[] command = execConfig.getCommand();
        log.debug("{}: Running \"exec\" command: {}", containerName, String.join(" ", command));
        final ExecCreateCmd execCreateCmd = dockerClient
            .execCreateCmd(containerId)
            .withAttachStdout(true)
            .withAttachStderr(true)
            .withCmd(command);

        String user = execConfig.getUser();
        if (user != null && !user.isEmpty()) {
            log.debug("{}: Running \"exec\" command with user: {}", containerName, user);
            execCreateCmd.withUser(user);
        }

View on GitHub (pinned to 8e549514e3)