docker compose up error (tested)
docker compose up fails for a handful of recurring reasons: a bad image reference, a typo in a service name, a tag that does not exist, or a port someone else is already using. We reproduced four of the most common errors ourselves on a live box running Docker 29.8.1 / Compose v5.5.1 and recorded the exact text each one prints, so you can match your error below instead of guessing.
1. Quick lookup: match your error text
| What you see | Meaning | Jump to |
|---|---|---|
invalid reference format | Bad characters/syntax in an image: value | Section 2 |
no such service | You named a service that isn't in the compose file | Section 3 |
manifest unknown / not found | The image tag doesn't exist in the registry | Section 4 |
port is already allocated | Something else on the host is using that port | Section 5 |
error getting credentials | Broken or missing Docker credential helper | Section 6 |
ContainerConfig KeyError | Legacy bug in the old Python docker-compose v1 | Section 7 |
2. "invalid reference format"
This means the image: value in your compose file isn't a syntactically valid image reference — usually a stray space, an unescaped special character, or a missing quote that merges two YAML values together. We put this in a compose file:
services:
web:
image: "bad image name with spaces"
Running docker compose -p forever-guidetest up gave exactly:
unable to get image 'bad image name with spaces': Error response from daemon: invalid reference format
Fix: image names can only contain lowercase letters, digits, and . _ - / (plus a :tag or @digest suffix). Spaces, uppercase letters in the repository path, and most punctuation are invalid. Print the resolved value with docker compose config to see exactly what YAML produced — this also catches cases where a missing quote or a bad environment variable substitution (${VAR} expanding to something odd) silently built a malformed string.
3. "no such service"
This fires when you tell Compose to start a service name that doesn't exist in the file, for example a typo or a service you renamed. With a compose file defining only web, we ran:
$ docker compose -p forever-guidetest up nonexistent-service-name
no such service: nonexistent-service-name
Fix: run docker compose config --services to list the service names Compose actually sees (useful if you're merging multiple -f files or using an extends:/profile setup, where a service can silently disappear). Then correct the name in your command or your override file.
4. "manifest unknown" / "failed to resolve reference ... not found"
This means the image exists but the tag you asked for does not, in the registry you're pulling from. We referenced a tag that doesn't exist:
services:
web:
image: alpine:this-tag-does-not-exist-12345
On this box (Docker 29.8.1, containerd image store), docker compose -p forever-guidetest up printed:
Error response from daemon: failed to resolve reference "docker.io/library/alpine:this-tag-does-not-exist-12345": docker.io/library/alpine:this-tag-does-not-exist-12345: not found
A plain docker pull of the same bad tag gave the identical message. Older Docker versions (and the classic image store) report this same condition as manifest unknown or manifest for IMAGE:TAG not found — the wording changed with newer Docker releases, but the cause is the same: the tag isn't in the registry.
Fix: check the real tags on the registry (for Docker Hub, the image's "Tags" page), fix typos (lts vs latest is a common one), and confirm you're pointed at the right registry if you use a private one — a missing registry prefix silently falls back to Docker Hub.
5. "error response from daemon": port is already allocated
This is the generic wrapper Docker uses for daemon-side failures; the specific reason is in the rest of the message. The most common one is a host port collision. We defined two services both publishing host port 8902:
services:
web1:
image: httpd:alpine
ports: ["8902:80"]
web2:
image: httpd:alpine
ports: ["8902:80"]
docker compose -p forever-guidetest up started web1 fine, then failed on web2 with:
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint forever-guidetest-web2-1 (...): Bind for :::8902 failed: port is already allocated
Fix: run ss -ltn or docker ps --format '{{.Names}}: {{.Ports}}' to see what already holds the port, then change your mapping (e.g. "8903:80") or stop the conflicting container. The same "Error response from daemon" wrapper also appears for other daemon-side problems (invalid bind-mount source paths, out-of-memory, permission errors on volumes) — the text after the colon tells you which one you hit.
6. "error getting credentials" (tested)
This means your Docker config points at a credential helper binary that Docker can't successfully run. We reproduced it three distinct ways using a throwaway DOCKER_CONFIG directory (so no real login state was touched):
$ cat config.json
{"credsStore": "nonexistenthelper"}
$ DOCKER_CONFIG=/tmp/dockercredtest docker pull alpine:latest
error getting credentials - err: exec: "docker-credential-nonexistenthelper": executable file not found in $PATH, out: ``
That's a global credsStore pointing at a helper that was never installed. A per-registry credHelpers entry fails identically, just scoped to the one registry:
$ cat config.json
{"credHelpers": {"ghcr.io": "nonexistenthelper2"}}
$ DOCKER_CONFIG=/tmp/dockercredtest docker pull ghcr.io/nonexistent/nonexistent:latest
error getting credentials - err: exec: "docker-credential-nonexistenthelper2": executable file not found in $PATH, out: ``
The third case is different: the helper binary exists and is on PATH, but it exits with an error of its own (a common real cause — a credential-helper binary that's installed but misconfigured, e.g. pointing at a keychain/vault it can't reach):
$ cat config.json
{"credsStore": "broken"}
$ PATH=/tmp/dockercredtest/bin:$PATH DOCKER_CONFIG=/tmp/dockercredtest docker pull alpine:latest
error getting credentials - err: exit status 1, out: ``
Note the different wording: executable file not found in $PATH (cases 1-2, the binary doesn't exist) versus exit status 1 (case 3, the binary exists but failed internally) — useful for telling the two apart. We also confirmed the lookalike NOT to confuse this with: a real wrong username/password on docker login gives a completely different message, Error response from daemon: Get "https://registry-1.docker.io/v2/": unauthorized: incorrect username or password — no mention of "credentials" or a helper at all, since that's an auth failure, not a credential-helper failure.
Fix: check the "credsStore" / "credHelpers" keys in ~/.docker/config.json. Confirm the referenced docker-credential-* binary is actually installed and on PATH (run which docker-credential-<name>); if it exists, run it directly to see its own error. If you don't need a helper at all, remove the key entirely to fall back to Docker's built-in (unencrypted) credential store.
7. "ContainerConfig" KeyError (legacy docker-compose v1 only)
This is a known bug in the old Python-based docker-compose v1 (not the docker compose v2 plugin used throughout this guide): after pulling a new image for a service, recreating the container could crash with a Python traceback ending in KeyError: 'ContainerConfig', because v1 tried to read fields from the old container's inspect data that no longer matched the new image's metadata format. This box only has Compose v2 installed, where this code path doesn't exist, so we could not reproduce it — this section is from the public GitHub issues describing the bug, not measured here.
Fix: this bug is specific to the unmaintained v1 CLI. The real fix is to stop using it: install the docker compose v2 plugin (run docker compose version to confirm you have it) and use docker compose with a space instead of the hyphenated docker-compose binary. If you're stuck on v1 for now, a manual workaround is docker compose rm -fsv <service> followed by docker compose up -d <service> to force a clean recreate instead of an in-place update.
8. General debugging approach
- Run
docker compose configfirst. It resolves all your YAML, environment variables, and includes/extends into the final config Compose will actually use — most "invalid reference" and silent-typo bugs show up here before you even try to start anything. - Add
--progress plain(or setCOMPOSE_PROGRESS=plain) if the default spinner output hides details on a pull or build failure. - For networking errors, check
docker psandss -ltnfor what's already bound before assuming Docker itself is broken. - If you only have DNS/header-level symptoms once the container is up (wrong headers, caching, HTTPS mismatches), check what your container's web server is actually sending with our HTTP header checker, not the compose logs.
Frequently asked questions
Why do I get invalid reference format but my image name looks fine?
Check for hidden issues: a trailing space, an environment variable that expanded to an empty or odd string, or uppercase letters in the repository path (only the tag may have uppercase). Run `docker compose config` to see the exact resolved value Compose will send to the daemon.
I fixed the typo but still get no such service, why?
Compose may be reading a different file than you think, especially with multiple -f flags, a committed override file, or COMPOSE_FILE set in your environment. Run `docker compose config --services` to see the service list Compose actually resolved.
Is manifest unknown the same as image not found?
Yes. Both mean the registry has no image+tag matching what you asked for. On Docker 29.8.1 we measured the daemon reporting it as "failed to resolve reference ... not found"; older Docker versions and some registries report it as "manifest unknown" or "manifest for IMAGE:TAG not found". The fix is the same either way: check the tag actually exists.
Does upgrading from docker-compose v1 to docker compose v2 fix ContainerConfig KeyError?
Yes, per the public bug reports this error is specific to the old Python v1 CLI's container-recreate logic. The v2 plugin (invoked as `docker compose`, no hyphen) rewrote that logic in Go and does not have this code path. We could not reproduce the bug at all on this box because only v2 is installed, which is itself evidence the issue is v1-specific.
My port error says a different message than 'port is already allocated', what now?
"Error response from daemon" is a generic prefix; everything after the colon is the real reason, and the daemon uses it for many unrelated failures (bad bind-mount paths, permission errors, out-of-memory kills). Read the text after "Error response from daemon:" literally — it names the actual subsystem (networking, storage driver, OOM killer) that rejected the request.
What does 'error getting credentials' actually mean?
We measured this three ways: your Docker config's credsStore or credHelpers points at a docker-credential-* helper binary that either doesn't exist ("executable file not found in $PATH") or exists but fails internally when run ("exit status 1"). It's unrelated to whether your username/password are correct — that's a separate "unauthorized" error from the daemon, not a credentials-helper error at all.
Written with AI assistance. Measured on 2026-10-02 with Docker 29.8.1 and Docker Compose v5.5.1 (the `docker compose` plugin, not the old Python `docker-compose`) on Linux. All commands used project name forever-guidetest and small/cached images (busybox:latest, httpd:alpine). Updated 2026-10-03: the credential-helper section is now measured too, using a scoped DOCKER_CONFIG pointed at a throwaway directory so no real Docker login state was touched. The ContainerConfig section remains from Docker's own docs and GitHub issues, not measured (only Compose v2 is installed on this box, which doesn't have that code path). PlainHeaders is our extension; Docker and Docker Compose are free.