Module
Redpanda
Testcontainers version
2.0.5
Using the latest Testcontainers version?
Yes
Host OS
OSX
Host Arch
ARM
Docker version
Client:
Version: 29.1.4-rd
API version: 1.52
Go version: go1.25.5
Git commit: 3c6914c
Built: Fri Jan 9 20:45:44 2026
OS/Arch: darwin/arm64
Context: default
Server:
Engine:
Version: 29.1.3
API version: 1.52 (minimum version 1.41)
Go version: go1.25.5
Git commit: fbf3ed25f893e6ce21336f1101590e40a13934f4
Built: Sun Dec 14 05:31:58 2025
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: v2.2.0
GitCommit: 1c4457e00facac03ce1d75f7b6777a7a851e5c41
runc:
Version: 1.4.0
GitCommit: 8bd78a9977e604c4d5f67a7415d7b8b8c109cdc4
docker-init:
Version: 0.19.0
GitCommit:
What happened?
RedpandaContainer throws java.lang.IllegalArgumentException: Requested port (9092) is not mapped when starting under testcontainers 2.x, making the container completely unusable.
Steps to Reproduce:
@Container
static RedpandaContainer redpanda = new RedpandaContainer(
"docker.redpanda.com/redpandadata/redpanda:v26.1.9");
Running any test that uses this container produces:
Caused by: java.lang.IllegalArgumentException: Requested port (9092) is not mapped
at org.testcontainers.containers.ContainerState.getMappedPort(ContainerState.java:175)
at org.testcontainers.redpanda.RedpandaContainer.containerIsCreated(RedpandaContainer.java:...)
Root Cause
RedpandaContainer.containerIsCreated() calls getMappedPort(9092) to write the correct --advertise-kafka-addr into the startup script before the container process begins. In testcontainers 1.x, Docker's random host port assignment happened at container creation time, so getMappedPort() was already valid inside containerIsCreated.
In testcontainers 2.x, the port assignment lifecycle changed: the ephemeral host port is only resolved after the container starts, not when it is created. containerIsCreated now fires too early — the port binding hasn't been populated yet — so getMappedPort() throws.
Proposed Fix
Replace the getMappedPort() call in containerIsCreated with a pre-allocated port strategy, similar to how some other testcontainers modules handle this:
At construction time, open a ServerSocket(0) to let the OS assign a free port, record that port number, then close the socket.
Use withCreateContainerCmdModifier to bind that specific host port to container port 9092 (instead of relying on Docker's random assignment).
Bake the pre-allocated port directly into the startup script / --advertise-kafka-addr flag — no lifecycle hook or getMappedPort() call required at all.
Return the pre-allocated port from getBootstrapServers().
Sketch of the change inside RedpandaContainer:
// Construction time — before any container lifecycle hooks run
private final int hostPort = findFreePort();
private static int findFreePort() {
try (ServerSocket s = new ServerSocket(0)) {
s.setReuseAddress(true);
return s.getLocalPort();
} catch (IOException e) {
throw new RuntimeException("Could not allocate a free port for Redpanda", e);
}
}
public RedpandaContainer(DockerImageName imageName) {
super(imageName);
withCreateContainerCmdModifier(cmd ->
cmd.withHostConfig(cmd.getHostConfig()
.withPortBindings(new PortBinding(
Ports.Binding.bindPort(hostPort),
ExposedPort.tcp(KAFKA_PORT)))));
withCommand(
"redpanda", "start",
"--kafka-addr", "PLAINTEXT://0.0.0.0:" + KAFKA_PORT,
"--advertise-kafka-addr", "PLAINTEXT://localhost:" + hostPort,
...
);
}
// containerIsCreated() can be removed entirely — it's no longer needed.
@Override
public String getBootstrapServers() {
return "localhost:" + hostPort;
}
Trade-off:
There is a small TOCTOU window between closing the ServerSocket and Docker binding the port. In practice this is negligible on development/CI machines, and it is the same pattern already used by other testcontainers modules (e.g. KafkaContainer in some configurations).
Relevant log output
Additional Information
No response
Module
Redpanda
Testcontainers version
2.0.5
Using the latest Testcontainers version?
Yes
Host OS
OSX
Host Arch
ARM
Docker version
Client: Version: 29.1.4-rd API version: 1.52 Go version: go1.25.5 Git commit: 3c6914c Built: Fri Jan 9 20:45:44 2026 OS/Arch: darwin/arm64 Context: default Server: Engine: Version: 29.1.3 API version: 1.52 (minimum version 1.41) Go version: go1.25.5 Git commit: fbf3ed25f893e6ce21336f1101590e40a13934f4 Built: Sun Dec 14 05:31:58 2025 OS/Arch: linux/arm64 Experimental: false containerd: Version: v2.2.0 GitCommit: 1c4457e00facac03ce1d75f7b6777a7a851e5c41 runc: Version: 1.4.0 GitCommit: 8bd78a9977e604c4d5f67a7415d7b8b8c109cdc4 docker-init: Version: 0.19.0 GitCommit:What happened?
RedpandaContainer throws java.lang.IllegalArgumentException: Requested port (9092) is not mapped when starting under testcontainers 2.x, making the container completely unusable.
Steps to Reproduce:
Running any test that uses this container produces:
Root Cause
RedpandaContainer.containerIsCreated() calls getMappedPort(9092) to write the correct --advertise-kafka-addr into the startup script before the container process begins. In testcontainers 1.x, Docker's random host port assignment happened at container creation time, so getMappedPort() was already valid inside containerIsCreated.
In testcontainers 2.x, the port assignment lifecycle changed: the ephemeral host port is only resolved after the container starts, not when it is created. containerIsCreated now fires too early — the port binding hasn't been populated yet — so getMappedPort() throws.
Proposed Fix
Replace the getMappedPort() call in containerIsCreated with a pre-allocated port strategy, similar to how some other testcontainers modules handle this:
At construction time, open a ServerSocket(0) to let the OS assign a free port, record that port number, then close the socket.
Use withCreateContainerCmdModifier to bind that specific host port to container port 9092 (instead of relying on Docker's random assignment).
Bake the pre-allocated port directly into the startup script / --advertise-kafka-addr flag — no lifecycle hook or getMappedPort() call required at all.
Return the pre-allocated port from getBootstrapServers().
Sketch of the change inside RedpandaContainer:
Trade-off:
There is a small TOCTOU window between closing the ServerSocket and Docker binding the port. In practice this is negligible on development/CI machines, and it is the same pattern already used by other testcontainers modules (e.g. KafkaContainer in some configurations).
Relevant log output
Additional Information
No response