← Back to Tutorials

When `docker-compose up` Fails: Systematic Troubleshooting of Common Errors

docker-composedockertroubleshootingdevopscontainerslogsnetworkingvolumespermissionsbuild-errors

When docker-compose up Fails: Systematic Troubleshooting of Common Errors

This tutorial is a systematic, command-driven approach to diagnosing and fixing failures when running docker-compose up (or docker compose up with the newer CLI). It focuses on repeatable steps rather than one-off fixes, so you can apply the same workflow to almost any Compose-related failure.


Table of Contents


1. Know Your Compose Variant and Versions

There are two common ways to run Compose:

They behave similarly, but error messages and some features differ. Start by identifying what you’re actually running.

docker version
docker compose version
docker-compose version || true

Typical outcomes:

Why this matters:

Also check the OS context:

uname -a

On macOS/Windows, Docker runs inside a VM; filesystem mounts and networking can behave differently than Linux.


2. First Pass: Reproduce Cleanly and Capture Evidence

When docker-compose up fails, avoid guessing. Capture the exact error, then expand your visibility.

Run with explicit project context and no stale leftovers

From the directory containing your compose.yaml / docker-compose.yml:

pwd
ls -la

Then:

docker compose up

If it fails quickly, rerun with more verbose output:

docker compose --verbose up

If output is too noisy, keep it but redirect to a file:

docker compose --verbose up 2>&1 | tee compose-debug.log

Check what Compose created before failing

Even if up fails, Compose may have created networks/containers.

docker compose ps
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'
docker network ls
docker volume ls

Inspect the failing container(s)

If a container exists but is exited:

docker logs <container_name>
docker logs --tail=200 <container_name>

If it crashes immediately, get the exit code:

docker inspect <container_name> --format '{{.State.ExitCode}}'
docker inspect <container_name> --format '{{.State.Error}}'

3. Validate the Compose Configuration Before Running

Many “runtime” failures are actually configuration problems.

Render the fully-resolved Compose config

This is one of the most powerful commands:

docker compose config

It expands:

If docker compose config fails, fix that first. Common messages include:

Check which file Compose is using

Compose looks for compose.yaml, compose.yml, docker-compose.yml by default. If you have multiple files, be explicit:

docker compose -f compose.yaml config
docker compose -f docker-compose.yml config

Verify environment variables used by Compose

If your compose file uses ${VAR} substitutions, confirm they’re set:

env | sort | less

If using an .env file, ensure it exists and is in the correct directory (Compose reads .env from the project directory by default):

ls -la .env
cat .env

To see what Compose thinks the environment is after interpolation, again use:

docker compose config

4. Categorize the Failure: Where Is It Breaking?

Most docker-compose up failures fall into one of these buckets:

  1. Docker daemon not reachable / permissions
  2. Network/port binding problems
  3. Volume mount / filesystem permissions
  4. Image pull failures
  5. Build failures
  6. Container starts then exits (app-level errors)
  7. Healthcheck/dependency issues
  8. DNS/service discovery issues
  9. Resource constraints (disk/memory/CPU)

The rest of this tutorial walks through each category with concrete commands and fixes.


5. Common Error Class: Docker Daemon / Permissions

Symptom: “Cannot connect to the Docker daemon”

Examples:

On Linux: check daemon status

systemctl status docker
sudo systemctl start docker
sudo systemctl enable docker

Check socket permissions:

ls -l /var/run/docker.sock

If you see something like root docker, your user may need to be in the docker group:

sudo usermod -aG docker "$USER"
newgrp docker

Then verify:

docker ps

Note: Using the docker group grants root-equivalent access to the host. In production environments, consider rootless Docker or tighter controls.

On macOS/Windows: Docker Desktop running?

Ensure Docker Desktop is started and healthy. Then:

docker ps

If Docker Desktop is running but docker ps fails, try restarting Docker Desktop and/or resetting Kubernetes (if enabled and interfering).


6. Common Error Class: Ports and Networking

Symptom: “Bind for 0.0.0.0:XXXX failed: port is already allocated”

This means something on your host is already using that port.

Find what’s using the port (Linux)

sudo ss -ltnp | grep ':8080'

Or:

sudo lsof -iTCP:8080 -sTCP:LISTEN -n -P

Find what’s using the port (macOS)

lsof -iTCP:8080 -sTCP:LISTEN -n -P

Fix options

  1. Stop the conflicting service (if safe):

    sudo systemctl stop nginx
  2. Change the published port in Compose (host side). If your compose maps 8080:80, change to 8081:80 and rerun.

  3. Bind to localhost only (reduces exposure):

    • Use 127.0.0.1:8080:80 style mapping in Compose (conceptually: host IP + host port -> container port).
    • Then access via http://127.0.0.1:8080.

Symptom: “network … not found” or “Pool overlaps”

If networks were partially created or you have conflicting subnets.

Inspect existing networks

docker network ls
docker network inspect <network_name>

Remove only the project’s networks

docker compose down

If the project name changed (e.g., directory rename), list networks and remove the specific one:

docker network rm <network_name>

If you see “Pool overlaps with other one on this address space”, you likely have a custom subnet conflicting with another Docker network or your corporate VPN. Fix by choosing a different subnet or removing the conflicting network.


7. Common Error Class: Volumes, Mounts, and File Permissions

Mount issues are among the most frequent Compose problems, especially across OSes.

Symptom: “Mounts denied” (Docker Desktop)

On macOS/Windows:

Fix:

Symptom: “no such file or directory” for a bind mount

Example:

Check the path exists on the host:

ls -la ./path/on/host

Remember: relative paths are relative to the Compose file’s directory (project directory), not your current shell directory if you run Compose elsewhere.

Confirm the resolved config:

docker compose config | sed -n '/volumes:/,/networks:/p'

Symptom: Permission denied inside container

Example:

Diagnose by checking ownership on host

ls -lan ./data
id

The container may run as a different UID/GID than your host user.

Inspect container user

If the container exists:

docker inspect <container_name> --format '{{.Config.User}}'

If empty, it runs as the image default (often root, but not always).

Practical fixes

  1. Chown the host directory to match container UID/GID (common for Linux dev setups):

    sudo chown -R 1000:1000 ./data

    (Replace 1000:1000 with the container’s expected UID/GID.)

  2. Run container as your user (development convenience):

    • Many images support user: "${UID}:${GID}" conceptually; ensure your environment exports them:
      export UID GID
      echo "$UID $GID"
    • Then rerun Compose.
  3. Use a named volume instead of a bind mount if you don’t need host visibility:

    docker volume ls
    docker volume inspect <volume>

Named volumes avoid many host filesystem permission problems because Docker manages them.


8. Common Error Class: Image Pull / Build Failures

Symptom: “pull access denied” / “manifest unknown” / auth errors

Confirm the image name and tag

Try pulling manually:

docker pull yourimage:yourtag

If it fails:

Authenticate to registries

For Docker Hub or generic registries:

docker login

For a specific registry:

docker login registry.example.com

For cloud registries (examples):

Symptom: Build fails during docker compose up --build

First, isolate the build:

docker compose build --no-cache

If it fails, build a single service:

docker compose build --no-cache <service_name>

Common build failure causes

  1. Missing build context files

    • Dockerfile references files not in context.
    • Diagnose by checking the build context directory and .dockerignore.
  2. Proxy / network issues during build

    • If apt-get or pip fails, test connectivity from host:
      curl -I https://deb.debian.org
    • If you’re behind a proxy, you may need to pass build args or configure Docker daemon proxy.
  3. Multi-arch mismatch

    • On Apple Silicon, pulling/building linux/amd64 vs linux/arm64 matters.
    • Check your platform:
      uname -m
      docker info | sed -n '/Architecture/,+2p'
    • Try building with a specific platform:
      docker buildx ls
      docker compose build --pull

9. Common Error Class: Containers Start Then Exit

This is the most important category to understand: Compose may be fine; the application is failing.

Symptom: Exited (1) or Exited (127) etc.

Step 1: Read logs

docker compose logs -f --tail=200

Or per-service:

docker compose logs -f --tail=200 <service_name>

Step 2: Inspect the container’s command and environment

docker compose ps
docker inspect <container_name> --format '{{json .Config.Cmd}}'
docker inspect <container_name> --format '{{json .Config.Entrypoint}}'
docker inspect <container_name> --format '{{json .Config.Env}}' | jq .

If you don’t have jq, omit it:

docker inspect <container_name> --format '{{json .Config.Env}}'

Step 3: Run an interactive shell in the image

If the container won’t stay up, start a one-off container:

docker compose run --rm <service_name> sh

If the image uses bash:

docker compose run --rm <service_name> bash

Now you can test:

Example checks:

env | sort
ls -la
cat /etc/os-release

Common exit-code patterns


10. Common Error Class: Healthchecks and Dependency Ordering

Symptom: Service depends on DB but starts too early

Compose’s depends_on controls startup order, not readiness (unless you use healthcheck conditions in some setups). The robust approach is:

Diagnose health status

docker compose ps
docker inspect <container_name> --format '{{json .State.Health}}' | jq .

Also view healthcheck logs:

docker inspect <container_name> --format '{{range .State.Health.Log}}{{println .Output}}{{end}}'

If a DB healthcheck is failing, the app may never see it “healthy.”

Test dependency connectivity from inside a container

For example, from the app container:

docker compose exec <app_service> sh -lc 'getent hosts db && nc -vz db 5432'

If nc isn’t installed, use alternatives:


11. Common Error Class: DNS / Service Discovery Inside Compose

Compose provides built-in DNS: services can reach each other by service name on the same network.

Symptom: “Name or service not known” when connecting to another service

Verify both services are on the same network

List networks for a container:

docker inspect <container_name> --format '{{json .NetworkSettings.Networks}}' | jq .

If they’re not on the same network, they can’t resolve each other.

Verify DNS resolution from inside the container

docker compose exec <service> sh -lc 'cat /etc/resolv.conf; getent hosts other_service'

If getent isn’t present:

docker compose exec <service> sh -lc 'nslookup other_service || true'

Common mistake: using localhost

Inside a container, localhost refers to the container itself, not another service and not the host. To reach another service, use its Compose service name (e.g., db, redis). To reach the host:

Test:

docker compose exec <service> sh -lc 'ping -c 1 host.docker.internal || true'

12. Common Error Class: Resource Limits (Memory/CPU/Disk)

Symptom: Random crashes, Killed, exit code 137, or build failures

Check disk usage

docker system df
df -h

If disk is full, builds and pulls fail in confusing ways.

Clean up unused resources (careful—see cleanup section):

docker image prune
docker builder prune

Check memory constraints (Docker Desktop)

Docker Desktop has configurable memory limits. If too low, builds and containers may be OOM-killed.

On Linux, check kernel messages:

dmesg -T | tail -n 100 | grep -i -E 'killed process|oom'

Check container resource usage

docker stats

If a service spikes memory and dies, it’s likely an application or configuration issue (e.g., Java heap too large, caching misconfigured).


13. Cleaning Up Safely (Without Nuking Everything)

When troubleshooting, you often need to remove broken containers/networks/volumes. Do it in increasing order of destructiveness.

Stop and remove only this project’s containers/networks

docker compose down

If you want to remove volumes created by the project (this deletes data):

docker compose down -v

Remove orphaned containers (from renamed services)

docker compose up --remove-orphans

Rebuild from scratch

docker compose down
docker compose build --no-cache
docker compose up

Prune unused Docker objects (global impact)

These commands affect the whole Docker host, not just your project:

docker container prune
docker network prune
docker volume prune
docker image prune
docker system prune

If you want the most aggressive cleanup (dangerous; deletes unused images, containers, networks, and build cache):

docker system prune -a

Use docker system df before and after to understand what you’re deleting.


14. A Repeatable Troubleshooting Checklist

Use this sequence to avoid thrashing:

  1. Confirm tooling

    docker version
    docker compose version
  2. Validate configuration

    docker compose config
  3. Run with visibility

    docker compose --verbose up 2>&1 | tee compose-debug.log
  4. Check container states

    docker compose ps
    docker ps -a
  5. Read logs

    docker compose logs -f --tail=200
  6. Inspect failing container

    docker inspect <container> --format '{{.State.Status}} {{.State.ExitCode}}'
    docker inspect <container> --format '{{.State.Error}}'
  7. Check ports

    sudo ss -ltnp | grep ':<port>' || true
  8. Check mounts

    ls -la <mounted_path>
  9. Test service-to-service connectivity

    docker compose exec <service> sh -lc 'getent hosts <other_service> && nc -vz <other_service> <port>'
  10. Clean project artifacts and retry

docker compose down
docker compose up --build

Closing Notes: How to Think About Compose Failures

A Compose “up” failure is rarely mysterious if you separate concerns:

The goal is to identify which layer is failing, then use the right command to confirm it. If you want, paste the exact error output (and your docker compose config output with secrets removed), and you can troubleshoot it using the workflow above.