Docker failed to set up container networking, on a runner
Docker failed to set up container networking is a wrapper around four unrelated failures, and the clause after the colon is the only part that tells you which one you have. The container is fine and the image is fine: the daemon could not give it the network it asked for, on this host, right now.

What this error means
A docker run or a docker compose up fails while starting a container, after the image is present and before anything inside it runs, and the message is long enough that people quote only the first half of it. The half that matters is at the end: a port that could not be bound, an address pool with nothing left in it, a firewall rule that could not be written, or a privileged port in a rootless daemon. We did not reproduce this one. Every shape of it depends on host state rather than on anything in a repository, and a clean runner has to be pushed into that state first, which teaches less than the checks below. The lines here come from named reports.
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint varnish (6400df0fc482c2eae663274595f7a1df47633ec29813d27d2b421e4a52f6b8a4): failed to bind host port 10.0.0.2:80/tcp: cannot assign requested addressRead the clause after the colon
The wrapper text is identical in all four cases, which is why searching for it returns four unrelated conversations. Match the tail of your own line against the table and the rest of this page narrows to one row.
Two of these are about the host being full, in different senses: no free port at the address you asked for, or no free subnet to allocate. The other two are about permission: a daemon that may not write firewall rules, or one that may not bind a low port.
| The clause after the colon | What ran out or was refused | First check |
|---|---|---|
failed to bind host port ... | The port or the address on this host | ss -ltnp for the port, and the address you asked for |
| "could not find an available ... IPv4 address pool" | Subnets in the default pools | docker network ls, then prune |
| An iptables or firewall rule failure | The daemon may not program rules | docker info and the daemon flags |
cannot expose privileged port | A rootless daemon binding below 1024 | The port number, and the rootless sysctl |
Common causes
The port or the address is not available
The commonest shape in CI, because service containers, a previous step and a test harness all want the same conventional port. It also covers an address that does not exist on this host: the report we quote asks for a port on an address the machine does not have, and the daemon answers that it cannot assign the requested address.
The default address pools are exhausted
Each network takes a subnet, Compose creates one per project, and nothing reclaims them until something prunes. A runner that brings up several stacks in one job, or a long-lived runner with a history, reaches the end of the pools and the next network cannot be allocated.
The daemon cannot program its firewall rules
A daemon running inside a container without the privileges it needs, a host where the rules are managed by something else, or a daemon started with rule creation disabled all end up unable to wire external connectivity. In our experience this is the cause whenever the failure appears only in a Docker-in-Docker job.
A rootless daemon asked for a privileged port
A rootless setup cannot bind below 1024 without an explicit change, and the error says so in a long clause about the port manager. yuzu-juice/ft_transcendence#129 is the report: a reverse proxy asking for port 80 under a rootless daemon, with the message naming both remedies and the port number as the third option.
How to fix it
Find out what already owns the port
- List listening sockets with the owning process before starting the container.
- If a service container has it, change the published port rather than the service.
- If nothing owns it, check the address in the publish flag exists on this host.
ss -ltnp | grep -E ':(80|443|5432)\b' || echo "port is free"
docker run -d -p 18080:80 nginx:1.27Reclaim networks, then widen the pools if you must
Pruning is the cheap fix and belongs in any job that brings up more than one stack. Widening the pools is a daemon change for a host that genuinely needs many networks at once, and it is worth doing deliberately rather than as a reaction.
docker compose down --remove-orphans
docker network prune --forceUse the runner daemon instead of nesting one
On a runner that already has Docker, a dind service adds a daemon whose networking you now have to configure. Drop it where you can. Where a tool insists on its own engine, give that engine the privileges it needs explicitly rather than adding flags until something works.
# only where nesting is genuinely required
docker run --privileged --network host docker:29-dindPublish high ports, or fix the rootless limit deliberately
Under a rootless daemon the simplest change is to publish a port above 1024 and let the test talk to that. Changing the unprivileged port floor or granting the capability is a host change, so make it in the runner image rather than in a step of one workflow.
docker run -d -p 8080:80 nginx:1.27 # not -p 80:80 under rootlessAddress pools, and how a pipeline exhausts them
Every Compose project creates its own network, and every network needs a subnet from the daemon default pools. A job that brings up several stacks, or a long-lived runner whose previous jobs left their networks behind, works through those pools until an allocation fails. The second wording in the table is that moment, and EricJMarti/inventory-hunter#185 is a plain report of it.
The daemon documentation we read on 2026-09-20 exposes the pools as a daemon setting, described as the default address pools for node specific local networks, with a base and a size for each entry. Widening them is the fix when a host genuinely needs many networks at once; removing networks nobody is using is the fix the rest of the time.
# what is allocated right now
docker network ls
docker network prune --force
# and, if the host really needs many networks:
# /etc/docker/daemon.json
# { "default-address-pools": [ { "base": "172.30.0.0/16", "size": 24 } ] }Firewall rules, and daemons inside containers
The Docker documentation states that Docker Engine creates its firewall rules using iptables by default, and the daemon reference lists the flag that disables that behavior, noting that without the masquerading rules containers cannot reach external hosts on a network other than the default bridge. A daemon that cannot write those rules is the third row of the table, and on a runner that daemon is nearly always one you started yourself.
That is the practical advice for CI: a hosted Linux runner already has a working daemon with working networking. A docker:dind service exists to give you one where none is available, and on a runner that has one it buys a second daemon, a second image cache, and this class of failure.
# prefer the daemon the runner already has
- run: docker run --rm -p 8080:80 nginx:1.27 nginx -t
# over a dind service plus DOCKER_HOST gymnasticsWhat the runner does about it
No repair, and no recorded run to quote. The six reproductions in this batch all ran on Latchkey latchkey-small runners, and this failure is the one we chose not to manufacture: pushing a clean runner into an exhausted address pool or a broken firewall state produces a log that documents the pushing rather than the failure. Nothing in the self-heal library targets container networking, and changing a host firewall under a running job is not a safe automatic action.
How to prevent it
- Publish high, unconventional ports in CI and let the tests read them from the environment.
- Bring stacks down and prune networks at the end of every job that creates them.
- Use the runner daemon rather than a nested one wherever the job allows it.
- Print the port list and the network list immediately before the step that starts containers.
Frequently asked questions
What does failed to set up container networking mean?
How do I fix could not find an available non-overlapping IPv4 address pool?
Why does docker compose up fail on networking in CI but not locally?
Does Docker need iptables to run containers?
Related guides
References
- Docker docs: packet filtering and firewalls
- Docker docs: dockerd, default address pools and the iptables flag
- magenx/Magento-2-docker-configuration#263: a host port that could not be bound
- EricJMarti/inventory-hunter#185: no non-overlapping IPv4 address pool left
- Docker documentation
- Docker build cache
- GitHub Actions documentation