Docker 29 Broke Traefik — Here's the Fix (and Why It Happened)
Docker 29 Broke Traefik — Here’s the Fix (and Why It Happened)
The “Everything Is Down” Moment
You ran apt upgrade on a Sunday evening on your Linux server. Seemed harmless. Docker updated to v29.0.0. You rebooted because why not.
Now every service behind your Traefik reverse proxy returns a 404. Or a 502. Or just… nothing. Your monitoring is screaming. Your personal projects are unreachable. Your CI pipeline is stuck. And if you’re running Coolify, Dokploy, or any platform that bundles Traefik, you can’t even access the management UI to fix it.
You check the Traefik logs and see this, repeating every few seconds:
ERR Failed to retrieve information of the docker client and server host error="Error response from daemon: client version 1.24 is too old. Minimum supported API version is 1.44, please upgrade your client to a newer version" providerName=dockerYour first thought: “I didn’t change anything in Traefik.”
You’re right. You didn’t. Docker changed something under you.
Let me save you the debugging. Here’s the fix.
The 30-Second Fix
This applies to Linux hosts running Docker Engine directly. If you’re using Docker Desktop (macOS or Windows), you’re not affected — updates are bundled automatically.
If your services are down right now and you need them back immediately, do this:
Edit (or create) /etc/docker/daemon.json:
sudo nano /etc/docker/daemon.jsonAdd this:
{ "min-api-version": "1.24"}If you already have content in daemon.json (storage driver, log driver, etc.), merge the key into the existing object. Don’t overwrite your whole config:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "min-api-version": "1.24"}The most common mistake is a missing or trailing comma. JSON is strict about this.
Then restart Docker:
sudo systemctl restart dockerImportant: Restarting Docker stops all running containers. If your containers have a restart policy (restart: unless-stopped or restart: always), they’ll come back on their own. If not, you’ll need to start them manually:
docker compose up -dDocker Swarm: This fix works the same on Swarm nodes. Apply it to all managers and workers. Swarm services will reschedule automatically after the daemon restarts.
Rootless Docker? The config file lives at ~/.config/docker/daemon.json and you restart with systemctl --user restart docker.
That’s it. Your services should come back within seconds. Traefik will reconnect to the Docker daemon, discover your containers, and routes will light up again.
Verifying it worked
Check Traefik’s logs:
docker logs traefik --tail 20You should no longer see the client version 1.24 is too old error. If you see Configuration received from provider docker, that’s a positive confirmation (this message only appears at INFO log level, which may not be your default).
The strongest verification is the API version check below.
Confirm your Docker API versions:
docker version --format '{{.Server.MinAPIVersion}}'This should now return 1.24 instead of 1.44.
Why this works: The min-api-version setting overrides Docker’s built-in floor. It tells the daemon to accept connections from clients using API version 1.24 and above, restoring the backward compatibility that Docker 29 removed. This config change keeps Docker 29 fully operational while re-enabling communication with older API clients. You’re still running Docker 29 with all its features — you’ve just told it to accept a wider range of client versions.
Is this safe? For now, yes. This setting only changes how Docker negotiates API versions with clients. The API version is a negotiation protocol that controls feature detection between client and server. It doesn’t touch encryption or authentication. The risk is that older API clients might miss newer fields or features, but Traefik only needs to read container labels and inspect networks. It doesn’t need API 1.44 for that.
The Real Fix: Update Traefik
The daemon.json workaround is a bandage. The actual fix is updating Traefik to v3.6.1 or later.
Traefik v3.6.1, released shortly after this incident, added automatic Docker API version negotiation. Instead of hardcoded v1.24, Traefik now queries the daemon for its supported version range and picks the highest mutually compatible version. This is how the Docker SDK is supposed to work.
If you manage Traefik directly (docker-compose, Dockerfile, etc.), change your image tag:
services: traefik: image: traefik:v3.6.1Or pull the latest:
docker pull traefik:v3.6.1Then restart:
docker compose up -d traefikIf you’re on the older standalone docker-compose, the command is docker-compose up -d traefik.
Once Traefik is on 3.6.1+, you can remove the "min-api-version" workaround from daemon.json and restart Docker again. Everything will keep working because Traefik now negotiates the API version correctly on its own.
If you can’t update Traefik directly
If you’re running a platform that bundles Traefik (Coolify, Dokploy, Appwrite, CapRover), you might not control the Traefik image version. In that case:
- Check if your platform has an update. Most of them shipped patches within days.
- Use the daemon.json workaround until the platform updates its bundled Traefik.
- Check the platform’s GitHub issues. This broke so many deployments that every affected platform has a thread about it.
What Actually Happened
Let me explain the technical chain of events, because understanding it helps you prevent similar breakages.
Docker’s API version floor
Docker Engine exposes a versioned API. Clients (CLI, SDK, third-party tools) negotiate which version to use during the initial handshake. Before Docker 29, the daemon supported API versions going all the way back to v1.24, which was introduced with Docker 1.12 in 2016. Nearly a decade of backward compatibility.
With Docker Engine v29.0.0 (released November 10, 2025), Docker raised the minimum supported API version to v1.44. API v1.44 corresponds to Docker Engine v25, released in late 2023.
This was deliberate and documented. Docker’s deprecation policy states that API versions are supported for a limited number of major releases. API 1.24 had been deprecated for years. Docker 29 finally enforced the deprecation.
The result: any tool compiled against an older Docker SDK that defaults to API v1.24 as its negotiation floor gets rejected immediately. No fallback. No graceful degradation. A hard error: client version 1.24 is too old.
Why Traefik specifically exploded
Traefik uses Docker’s official Go SDK (github.com/docker/docker/client) for container discovery. It reads container labels, figures out routing rules, and dynamically updates its configuration.
The problem is in how the Go Docker SDK initializes. When you create a new client with client.NewClientWithOpts(), the SDK defaults to negotiating from API v1.24. This has been the SDK’s default since it was written. It was never a problem because Docker always accepted v1.24.
Docker 29 stopped accepting it. The negotiation fails before Traefik can even list containers. No containers discovered means no routes configured means every request hits a 404 or 502.
This affected all Traefik versions through v3.6.0, including v2.x. Traefik was using an SDK default (API v1.24) that Docker 29 no longer accepts.
It’s Not Just Traefik
Traefik got the most attention because a broken reverse proxy takes down everything behind it. But Docker 29’s API floor broke a wide range of tools:
| Tool | What Broke | Fix |
|---|---|---|
| Traefik (v3.6.0 and earlier) | Container discovery, all routing | Update to v3.6.1+ |
| Portainer (before v2.33.5) | Can’t connect to Docker environments | Update to v2.33.5+ (LTS) or v2.36.0+ (STS) |
| Watchtower | Can’t query containers for updates | Switch to nickfedor/watchtower (original containrrr/watchtower is unmaintained) |
| LazyDocker | Docker connection fails | Update to v0.24.2+ |
| Dokploy | Bundled Traefik fails | Update Traefik image to v3.6.1 |
| Coolify | Bundled Traefik fails | Check for Coolify update |
| Appwrite | Bundled Traefik v2.11 fails | Update to Appwrite version using Traefik v3 |
| JetBrains IDEs | Docker plugin throws 400 errors | Update IDE / Docker plugin |
| Spring Boot (Testcontainers) | docker-java defaults to API v1.32 | Update to Spring Boot 3.5.8+ (includes workaround), or set api.version=1.44 in docker-java.properties |
| Swarmpit | Docker API calls fail | No fix: project is archived |
| CapRover | Docker API connectivity | Check for update |
| CasaOS | Docker API connectivity | Check for update |
| cAdvisor | Metrics collection stops | Update to v0.53.0+ |
The pattern repeats across every entry: the tool uses a Docker SDK with a hardcoded minimum version below 1.44, Docker 29 rejects the connection, and the tool can’t communicate with the daemon.
Swarmpit is the saddest entry on that list. The project is archived. No fix is coming. Docker 29 finished what abandonment started.
Timeline
For the record, here’s how this played out:
- Nov 10, 2025 — Docker Engine v29.0.0 released. Minimum API version raised to v1.44. Traefik immediately breaks for everyone who auto-updates.
- Nov 10-11, 2025 — Reports flood in. Traefik GitHub issue #12253 is filed. The Docker Community Forums thread explodes. The Traefik community forum fills up. Coolify, Dokploy, and Appwrite all see the same issue.
- Nov 11, 2025 — Community identifies the
daemon.jsonworkaround and theDOCKER_MIN_API_VERSIONenvironment variable as immediate workarounds. - Nov 12, 2025 — Traefik maintainer PR #12256 adds automatic API version negotiation. Community test builds appear on Docker Hub.
- Nov 13-14, 2025 — Traefik v3.6.1 released with the fix. Portainer ships v2.33.5 and v2.36.0 with updated API support. LazyDocker ships v0.24.2.
- Nov 2025 onward — The rest of the tooling world catches up. Spring Boot, JetBrains, and others ship fixes over the following weeks.
From “everything is broken” to “official fix available”: roughly 48 hours. Solid open-source incident response. But if you were one of the people whose services went down on a Sunday night, it probably felt a lot longer.
Takeaways
For your infrastructure
Pin your Docker version in production. Docker 29’s release notes documented the API version change. But if Docker auto-updates via your package manager (as it does on Ubuntu with the official repository), you get the breaking change whether you read the notes or not.
On Ubuntu/Debian:
sudo apt-mark hold docker-ce docker-ce-cli containerd.ioWhen you’re ready to upgrade, unpin:
sudo apt-mark unhold docker-ce docker-ce-cli containerd.ioPin your Traefik version too. Using traefik:latest means you get updates automatically, which is usually fine, but it also means you can’t predict when behavior changes. Use explicit version tags like traefik:v3.6.1.
Keep a daemon.json backup. This file is tiny but critical. If you have it backed up or version-controlled, you can apply the workaround in under a minute instead of googling for it.
For the broader picture
A huge number of Docker-adjacent tools depended on an API version Docker deprecated years ago. The SDK default of v1.24 was never updated because Docker was always backward-compatible. Tools that were actively maintained shipped fixes within days. Tools that weren’t (Swarmpit, older CasaOS setups) are now permanently broken on Docker 29+.
The min-api-version escape hatch is Docker acknowledging the pain with a temporary lever. Eventually, even that setting may go away.
If you maintain a tool that talks to Docker, check your SDK’s default API version negotiation. If it’s hardcoded to a minimum, make it dynamic. The Traefik PR that fixed this was a few dozen lines of code.
Update Traefik. Pin your Docker version. The order is up to you.
Related Posts
How to optimize a Go deployment with Docker
Optimize your Go deployment with Docker using multi-stage builds. Reduce image size from 1GB to 15MB with practical Dockerfile examples.
How to Merge PGN Files in F#: Streaming, Performance, and Discriminated Unions
How I built a CLI tool to merge chess PGN files using F#'s type system, streaming I/O, and functional patterns — merging gigabytes of games with 64 KB of memory.
Why Japanese Websites Look Overloaded: Density, Tokyo, and Trust
Why Japanese websites look overloaded, how Tokyo's dense visual environment helps explain the pattern, and why 'clutter' is often the wrong UX question.