"can't initialize iptables table `nat'": Docker-in-Docker on Ubuntu 26.04
ubuntu-latest is moving from Ubuntu 24.04 to 26.04 between October 19 and November 19, 2026 (what else changes). The 26.04 image runs kernel 7.0, which builds the legacy iptables tables as modules and does not load them: ip_tables, iptable_filter, iptable_nat, ip6_tables and ip6table_filter. On 24.04 they were loaded. Docker on the runner itself uses nftables, so it is fine, but a container that calls iptables-legacy cannot load them, and a dockerd inside it stops at its first NAT rule.
What it looks like
With the dev container docker-in-docker feature, the job log shows only the retry line, four times:
(*) Failed to start docker, retrying... (*) Failed to start docker, retrying... (*) Failed to start docker, retrying... (*) Failed to start docker, retrying... Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
The reason is in /tmp/dockerd.log inside the container, which the feature's docker-init.sh writes and nothing prints:
failed to start daemon: Error initializing network controller: ... failed to create NAT chain DOCKER: iptables v1.8.11 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Your own iptables-legacy calls in a container fail the same way, with filter instead of nat.
Why the feature picks legacy
Versions 2 and 3 of the feature choose the iptables alternative when the image is built, from the image's own distribution: iptables-nft only when the image itself is Ubuntu 26.04, and iptables-legacy for everything else, including Debian bookworm and trixie and Ubuntu 22.04 and 24.04. The :2 tag stopped at 2.17.0 in May 2026 and :3 at 3.1.0, so neither gets a later fix. Version 4.0.0 (June 2026) moved the choice to container start, on by default (iptablesSwitchAtRuntime), and uses legacy only when the host has ip_tables loaded (devcontainers/features #1666).
Where the reports came from
- A dev container on
python:3.14-bookwormwithdocker-in-docker:2, locked to 2.17.0, passed on the 24.04 image 20261025.353.1 and failed on every run on the 26.04 image 20261025.179.1, with the four retry lines and thenpgrep -x dockerd(docker-autoheal #143). - A project that uses the feature found the
nattable line above only by reading/tmp/dockerd.logfrom inside the container (container-base #225). - A diagnostic run on
ubuntu-latest(26.04, kernel 7.0) showedCONFIG_IP_NF_IPTABLES_LEGACY=mwithiptable_filter.kopresent but not loaded;iptables-legacyfailed in a container untilsudo modprobe iptable_filterran on the host (aios #2567).
Fix: move the feature to version 4
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:4": {}
}
If the repository has devcontainer-lock.json, update its docker-in-docker entry too: it holds the exact version and digest, and the failing project's lock still said 2.17.0. A prebuilt dev container image keeps the old choice until you rebuild it. If the container's entrypoint runs as a non-root user, use 4.1.3 or later (#1747). Version 2 to 4 is two major versions, so read the feature's options before switching.
Or load the modules on the runner
- run: sudo modprobe -a ip_tables iptable_filter iptable_nat ip6_tables ip6table_filter
Run this before the step that starts the container. It works for any container that uses iptables-legacy, not only the feature, and the project in aios #2567 does this in CI. On a self-hosted 26.04 host, load them at boot instead, with a file in /etc/modules-load.d/ that lists the five modules.
Pinning the job to runs-on: ubuntu-24.04 also works, until GitHub retires that image.
Telling it apart
- On the runner,
lsmod | grep -E '^(ip_tables|iptable_nat) 'prints nothing on 26.04. - Inside the container,
iptables --versionsays(legacy)or(nf_tables). A dockerd that fails with(nf_tables)in its log is a different problem. - Look at "Set up job": the Runner Image group shows the image. Until November 19 a re-run can land on the other image, so a green re-run proves nothing.
Other 26.04 failures
- pg_dump 18 on Ubuntu 26.04: PostgreSQL on the image and from apt is 18, so dumps start with
SET transaction_timeout = 0and a PostgreSQL 16 service rejects them with "unrecognized configuration parameter". - Postgres never starts in Docker on Ubuntu 26.04: newer kernels such as 7.0.0-42 run container processes as
docker-default//&unconfined, so they cannot signal each other andgosuhangs at 100% CPU; reported on self-hosted runners so far. - "client version ... is too old" on Ubuntu 26.04: Docker 29 refuses clients below API 1.40, so older Testcontainers fails with "Could not find a valid Docker environment".
- apt on Ubuntu 26.04: renamed and removed packages.
- "coreutils: unknown program": most core tools are uutils.
See failed jobs from IntelliJ IDEA
Pipeline Inbox for GitHub Actions Workflows, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, lists the runs of all your repositories in an IDE tool window, with their jobs and steps, and your current branch's runs are in the status bar. Reading is free; re-running failed jobs, cancelling, running workflows and reviewing deployments are Pro (US$1.50 a month, with a 30-day trial).
Get it on JetBrains Marketplace
GitHub and GitHub Actions are trademarks of GitHub, Inc.; Ubuntu is a trademark of Canonical Ltd.; Docker is a trademark of Docker, Inc.; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with, sponsored or endorsed by GitHub, Inc., Canonical, Docker, Inc. or JetBrains.
More: "The ubuntu-latest label will migrate to Ubuntu 26" · Postgres never starts in Docker on Ubuntu 26.04 · GitHub Actions plugins for IntelliJ IDEA compared · 日本語