testcontainers/testcontainers-java · error · IllegalStateException

copyFileFromContainer can only be used when the Container…

Error message

copyFileFromContainer can only be used when the Container is created.

What it means

copyFileFromContainer reads a file out of the container via the Docker copy-archive API, which requires the container to exist. If getContainerId() is null it throws IllegalStateException — there is no container to copy from yet.

Solutions

  1. Call start() and let the process complete before copying files out
  2. Check isCreated()/isRunning() before copying, or guard with getContainerId() != null
  3. Fix any earlier exception that prevented container startup
  4. Use execInContainer or wait strategies to ensure the file exists after startup

Example fix

// before
GenericContainer c = new GenericContainer<>("alpine:3");
String content = c.copyFileFromContainer("/tmp/out.txt", is -> new String(is.readAllBytes()));
c.start();
// after
c.start();
String content = c.copyFileFromContainer("/tmp/out.txt", is -> new String(is.readAllBytes()));
Defensive patterns

Strategy: validation

Validate before calling

if (container.getContainerId() == null || !container.isRunning()) throw new IllegalStateException("container must be started before copyFileFromContainer");

Try / catch

try { return container.copyFileFromContainer(path, fn); } catch (IllegalStateException e) { if (e.getMessage().contains("copyFileFromContainer")) { throw new IllegalStateException("Forgot to start container before reading " + path, e); } throw e; }

Prevention

When it happens

Trigger: Invoking copyFileFromContainer(path, fn) on a container that was never started (or never reached created state), e.g. reading logs/results files in a test before start().

Common situations: Reading an output file produced by the container before the container ran; calling copy on a fresh GenericContainer in a helper; failing start swallowed earlier so the ID was never set.

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/d3d2d4fe1c55eb84. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/testcontainers/containers/ContainerState.java:406

            inputStream -> {
                try (FileOutputStream output = new FileOutputStream(destinationPath)) {
                    IOUtils.copy(inputStream, output);
                    return null;
                }
            }
        );
    }

    /**
     * Streams a file which resides inside the container
     *
     * @param containerPath path to file which is copied from container
     * @param function function that takes InputStream of the copied file
     */
    @SneakyThrows
    default <T> T copyFileFromContainer(String containerPath, ThrowingFunction<InputStream, T> function) {
        if (getContainerId() == null) {
            throw new IllegalStateException("copyFileFromContainer can only be used when the Container is created.");
        }

        DockerClient dockerClient = getDockerClient();
        try (
            InputStream inputStream = dockerClient.copyArchiveFromContainerCmd(getContainerId(), containerPath).exec();
            TarArchiveInputStream tarInputStream = new TarArchiveInputStream(inputStream)
        ) {
            tarInputStream.getNextTarEntry();
            return function.apply(tarInputStream);
        }
    }
}

View on GitHub (pinned to 8e549514e3)