Docker Error Guide: 'Error initializing network controller' Daemon Startup Failure
Fix dockerd 'Error initializing network controller' bridge and NAT failures: repair iptables, firewalld, the docker0 bridge, ip_forward, and corrupt network state.
- #docker
- #troubleshooting
- #errors
- #networking
Exact Error Message
dockerd refuses to finish starting and the service stays in a crash loop. The journal shows the daemon dying during network setup:
failed to start daemon: Error initializing network controller: Error creating default "bridge" network: Failed to program NAT chain: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables: Permission denied (you must be root).
Two other forms of the same failure are common. A leftover bridge with attached endpoints blocks recreation:
Error initializing network controller: could not delete the default bridge network: network bridge has active endpoints
And a libnetwork-level bridge conflict:
Error initializing network controller: libnetwork: bridge device with non default name docker0 must be created manually
Because this happens before the daemon accepts connections, every docker command fails with Cannot connect to the Docker daemon.
What It Means
When dockerd starts, libnetwork builds the default bridge network: it creates (or reuses) the docker0 Linux bridge, assigns its subnet, and programs the iptables/nftables NAT and FILTER chains (DOCKER, DOCKER-USER, masquerade rules) that give containers outbound connectivity and port publishing. “Error initializing network controller” means one of those steps failed, so the daemon aborts rather than run without a functioning default network.
The root is almost always host-side: the firewall backend won’t let Docker program its chains, the docker0 bridge already exists in a conflicting state, IP forwarding is disabled in the kernel, or libnetwork’s persisted state in /var/lib/docker/network is stale or corrupt after an unclean shutdown.
Unlike most container errors, this one blocks the entire daemon rather than a single workload. There is no partial degraded mode — if the default bridge network cannot be built, dockerd exits and systemd will restart it, fail again, and eventually back off into a failed state. That makes the journal the single most important diagnostic: the controller logs the exact sub-step that failed (NAT chain creation, bridge deletion, subnet assignment) immediately before the daemon dies, and that one line distinguishes an iptables problem from a corrupt-state problem from a leftover-bridge problem.
Common Causes
- iptables/nftables can’t be programmed — wrong backend (
nftablesvsiptables-legacy), missingiptable_natmodule, or rules locked by another tool. docker0bridge conflict — a manually created or leftoverdocker0with the wrong driver/subnet.- Leftover network state after a crash —
bridge has active endpointsfrom containers that were never cleanly stopped. - IP forwarding disabled —
net.ipv4.ip_forward = 0prevents NAT, and some versions refuse to start. - firewalld interference — firewalld flushing or owning the chains Docker expects.
- Overlapping subnet — the
bridgepool (default172.17.0.0/16) clashing with a host route or VPN. - Corrupt
/var/lib/docker/network— the libnetwork boltdb left inconsistent.
How to Reproduce the Error
Create a conflicting docker0 bridge before the daemon starts, then start it:
sudo systemctl stop docker
sudo ip link add docker0 type bridge
sudo ip addr add 10.10.0.1/24 dev docker0
sudo systemctl start docker
The daemon finds a docker0 it did not create with an unexpected subnet and fails to initialize the controller. Disabling forwarding reproduces the NAT-path failure:
sudo sysctl -w net.ipv4.ip_forward=0
sudo systemctl restart docker
Diagnostic Commands
Read the exact failure from the daemon journal — this classifies the cause:
sudo journalctl -u docker --since "10 min ago" --no-pager | grep -i 'network controller\|bridge\|iptables\|nat'
sudo systemctl status docker
Check which iptables backend is active and whether the NAT chains exist:
sudo iptables -t nat -L DOCKER -n 2>&1 | head
sudo update-alternatives --display iptables # legacy vs nft
sudo nft list tables 2>/dev/null
Confirm IP forwarding and inspect the bridge and persisted network state:
sysctl net.ipv4.ip_forward
ip -d link show docker0
sudo ls -l /var/lib/docker/network/files/
If firewalld is present, check whether it owns the zone Docker needs:
sudo firewall-cmd --get-active-zones 2>/dev/null
Step-by-Step Resolution
-
Enable IP forwarding if it is off — make it persistent so it survives reboots:
sudo sysctl -w net.ipv4.ip_forward=1 echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-docker.conf -
Fix the iptables backend. If the host runs
nftablesbut Docker expects legacy chains (or vice versa), align them and reload modules:sudo modprobe iptable_nat br_netfilter sudo update-alternatives --set iptables /usr/sbin/iptables-legacy # if needed -
Remove a conflicting
docker0bridge so Docker recreates it cleanly:sudo systemctl stop docker sudo ip link set docker0 down sudo ip link delete docker0 -
Reset stale network state when you see
active endpointsor corruption. Stop the daemon and clear the libnetwork db (containers’ network config is rebuilt on next start):sudo systemctl stop docker sudo rm -rf /var/lib/docker/network/files/ sudo systemctl start docker -
Reconcile with firewalld. Restart firewalld before Docker, or add Docker’s interface to a trusted zone so its chains survive:
sudo systemctl restart firewalld sudo systemctl restart docker -
Resolve an overlapping subnet by setting a non-conflicting default pool in
/etc/docker/daemon.json:{ "default-address-pools": [ { "base": "10.200.0.0/16", "size": 24 } ] }
After each change, sudo systemctl restart docker and confirm docker info returns and docker network ls shows the bridge network.
Resolve the causes in the order above rather than jumping straight to deleting state. Enabling ip_forward and aligning the iptables backend are non-destructive and fix the majority of cases. Deleting /var/lib/docker/network/files/ is safe for the network database specifically — Docker rebuilds default networks and re-attaches running containers’ configuration on next start — but it is still the heaviest hammer, so reserve it for when the journal explicitly reports corruption or active endpoints that no graceful container stop can clear. Never rm -rf /var/lib/docker wholesale to fix a network error; that destroys every image, volume, and container on the host for a problem that lives in one subdirectory.
How to Prevent the Issue
- Never manually create or rename
docker0; let the daemon own its default bridge. - Pin the iptables backend (legacy vs nft) consistently across the host and document it, especially after distro upgrades that flip the default.
- Keep
net.ipv4.ip_forward=1in/etc/sysctl.d/so a reboot can’t silently break NAT. - Stop containers cleanly (
docker stop/compose down) before host shutdown to avoidactive endpointson next boot. - If firewalld is required, integrate it with Docker’s
DOCKER-USERchain rather than flushing all rules.
Related Docker Errors
- Docker Error Guide: ‘port is already allocated’ — once the network controller is healthy, host port conflicts are the next class of publishing failure.
- Browse more Docker troubleshooting guides for DNS, registry, and storage errors.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.