DevOps

Fix Docker Compose "unknown flag: --iidfile" Build Error

The flag Compose added is real; the CLI parsing it is the part that is too old. Find which docker binary your build actually runs, then fix that one.

Mahdi Ben RhoumaMahdi Ben Rhouma
Updated
7 min read

TL;DR#

docker-compose 1.28 and later always appends --iidfile to the docker build command it runs under the hood. That flag only exists from Docker 17.06 onward (moby/moby#32406). If the docker binary Compose actually invokes is older than that — a CentOS/RHEL distro package, a Red Hat fork, a CI image pinned years ago — its argument parser rejects the flag before it ever reaches the daemon, and you get unknown flag: --iidfile. The fix is to upgrade that docker CLI binary to a current release, not to patch the Compose file.

text
$ docker-compose up
Building tomcat
unknown flag: --iidfile
See 'docker build --help'.
ERROR: Service 'tomcat' failed to build

This is the exact error from the original report (Stack Overflow, 67010408, 8 votes, 12k+ views): a node:alpine-based service built through a docker-compose.yml build: block.

Why it happens#

docker-compose (the Python v1 CLI, versions 1.29.0 and 1.29.1 included) builds each service by shelling out to the local docker executable with a fixed set of flags, and from 1.28 that includes --iidfile <tempfile> so Compose can read the built image's ID without scraping stdout. --iidfile is a flag of the docker build command itself, added in Docker 17.06 (moby/moby#32406, merged into that release line). Flag parsing happens inside the CLI binary before any request reaches the Docker daemon — the version that matters is whichever docker executable is first on PATH when Compose runs, which is not always the daemon version a developer checked with docker version on their own machine.

That is confirmed directly on the upstream issue (docker/compose#8296): the first report came from docker-compose 1.29.0 paired with Docker version 1.13.1 — described by a Docker maintainer as "a very old version of Docker that reached EOL over 4 years ago", most likely a Red Hat/CentOS fork with its own packaging that lags upstream Docker releases. A second, separate report on the same thread hit the identical error from inside a Jenkins container, with docker -v there showing Docker 20.10.14 — a current release, not an EOL binary like the first report. Maintainer thaJeztah asked "Are you sure those commands are running in the same environment?", suspecting a CLI/daemon mismatch between the Jenkins build step and the developer's own machine; the thread ends without that being confirmed. Same symptom as the first report, but the second case's cause was never pinned down on the thread.

Reproduced locally (30 September–6 October 2026, Docker Engine 29.7.2 host): running docker build --iidfile ./id.txt . through the docker:17.05 CLI image — one release line before --iidfile existed — reproduces the exact error string:

text
$ docker run --rm docker:17.05 docker build --iidfile /tmp/id.txt .
unknown flag: --iidfile
See 'docker build --help'.

docker build --help run through that same docker:17.05 image lists no --iidfile option at all, while the current host's docker build --help does. Running the identical docker build --iidfile ./id.txt -t test . with a current Docker CLI succeeds and writes the image digest to id.txt — the flag itself was never the problem; only the CLI version parsing it was.

Fix#

1. Find which docker binary Compose is actually calling, not the one you last checked by hand — PATH order, a container, or a CI runner can point Compose at a different binary than your interactive shell:

bash
which docker
docker version --format '{{.Client.Version}}'
docker build --help | grep iidfile

If the last command prints nothing, that binary predates 17.06 and will reject --iidfile from any Compose ≥ 1.28. On a separate report of this same error (docker/compose#8296, a Jenkins CI run), docker-compose version showed 1.29.1 while docker -v printed 20.10.14 — Compose and the daemon can be upgraded independently of the docker client binary on PATH, which is exactly the gap that produces this error even when "docker looks fine".

2. Upgrade that docker CLI/engine to a currently supported release (https://docs.docker.com/engine/install/). On the Red Hat fork case from the upstream issue, this means uninstalling the distro's forked docker package and installing the official Docker Engine packages for CentOS/RHEL — back up images pushed to a registry and volume data first, since the fork's image storage is not guaranteed compatible with upstream Docker.

bash
# Debian/Ubuntu example — replace with the official steps for your distro
sudo apt-get remove docker docker-engine docker.io
curl -fsSL https://get.docker.com | sh
docker build --help | grep iidfile   # now present

3. If you cannot upgrade immediately, pin docker-compose to 1.27.x or earlier (1.26.2 below) and leave COMPOSE_DOCKER_CLI_BUILD unset — on these releases --iidfile is never added unless that variable is explicitly set to a truthy value, as a stopgap only:

bash
pip install "docker-compose==1.26.2"

Treat this as temporary: it hides the symptom without closing the version gap, and the next flag a newer Compose release adds to its docker build call can reopen the same failure.

Verify the fix#

bash
docker-compose build
docker-compose up

The build log should show the normal layer-by-layer docker build (or BuildKit) output with no unknown flag line, and the service should start. Re-run the version check from step 1 (docker build --help | grep iidfile) once more after the upgrade: it should now print the --iidfile string line, confirming the exact binary Compose calls, not just the one in your interactive shell, moved past 17.06. If you upgraded the CLI only and the daemon itself is still the old Red Hat fork, docker-compose up can now fail differently — for example on a volume or network error — because flag parsing succeeded but the daemon underneath still behaves like the EOL fork; that is a separate upgrade (the daemon, not just the client) and a separate error to diagnose on its own. If the next failure says client version is too old, check the Docker API range and the client making the request; that daemon response needs a different diagnosis from an unknown CLI flag.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

A specific edge case: the binary your CI step runs is not the one you tested#

The Jenkins report on the upstream issue is the case worth remembering: the build failed inside the Jenkins container while the developer's own machine built fine, and the maintainer's working theory — never confirmed on the thread — was that the CLI resolved on PATH inside the Jenkins step was not the same one the developer had just checked by hand. Checking docker --version interactively proves nothing about what a CI job, a Makefile target, or a wrapper script resolves on PATH. Pin and check the version inside the exact environment that runs the build, not next to it.

If your service build already uses a bind-mounted node_modules volume like the original report's docker-compose.yml (volumes: - /app/node_modules), the Docker Compose dev environment guide covers the named-volume variant of that trick, which avoids the host node_modules clobbering the one installed inside the container once the build itself succeeds again. A YAML environment: block written as a list item under a mapping key is a different, unrelated Compose error — see the Compose "invalid type" / "unexpected type map" fix if that is the error actually in hand. And if the next failure after a successful build is the app container connecting to Postgres on its own loopback address instead of the Compose service name, that is covered separately in the ECONNREFUSED-to-Postgres fix for Docker Compose.

A version mismatch between a tool and the binary it shells out to rarely announces itself as a version error — it surfaces as a flag the older binary has never heard of. Checking the exact binary on the exact PATH a build step uses settles it faster than reading through changelogs guessing which side moved.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote