Intro
When Docker works, it feels invisible: a container starts, serves traffic, and shuts down on command. When it breaks, the error message can read like a riddle. This guide collects the Docker CLI errors most often seen in development and production, explains what each message actually means, and gives you the exact fix plus the command to verify it.
We cover Docker for Linux, macOS, and Windows, including Docker Desktop and Docker Engine, with special attention to docker compose and common image, container, network, and volume failures. Each section starts with the error text you will see, then shows the cause, the fix, and a later check to confirm the problem is gone.
This is not a reference manual. It is a troubleshooting path: observe first, change one thing, verify, then move on. You can use it during an incident or as a checklist before your next deploy.
1. Environment and Version Inventory
Before fixing anything, know your version and context. Many errors are version-specific: a flag that works in Docker 23 may not exist in Docker 20, and Docker Desktop behaves differently from Docker Engine on Linux.
Start with a read-only inventory:
docker version
docker info
docker version shows client and server versions. If the server version is missing, your client cannot reach the daemon. docker info prints the storage driver, logging driver, root directory, and importantly the number of running containers and images. It also shows warnings: no swap limit support, no cgroup v2, or a missing bridge network.
For Docker Context, which can silently target a remote or rootless daemon, list contexts:
docker context ls
If you see a context named remote-prod that you forgot to switch away from, every docker run command will try to use that remote daemon. Switch back with docker context use default.
Practical inventory commands:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker images | head -n 10
docker system df
The first shows running containers with names, status, and ports; the second shows recently built or pulled images; the third shows disk usage by images, containers, volumes, and build cache. docker system df is often the first hint that a build is failing because the disk is full (error: no space left on device).
For a Compose project:
docker compose ps
docker compose config
The config command validates and prints the merged compose file, showing environment variable substitution and default values. A common mistake is to edit docker-compose.yml but run docker compose in a different directory; docker compose ps will list no containers, and you may think the service is down.
As a rule: record the output of these commands before changing anything. You need a baseline to compare against.
2. Safe Configuration Path
Configuration errors are the most common source of Docker CLI failures. The fix is to change one configuration file or one environment variable at a time, then validate.
2.1 Docker daemon configuration (daemon.json)
Most daemon settings live in /etc/docker/daemon.json on Linux or under Settings > Docker Engine in Docker Desktop. A missing comma or wrong key will prevent the daemon from starting. On Linux, after editing, run:
sudo dockerd --validate
This checks the syntax without starting the daemon. Then restart Docker:
sudo systemctl restart docker
If the daemon fails to start, read the journal:
sudo journalctl -u docker --since "10 minutes ago" -f
A typical error: failed to start daemon: error initializing graphdriver: /var/lib/docker contains several valid graphdrivers. This means you changed the storage driver in daemon.json but existing data uses another driver. The safe path is to revert the change and plan a migration.
2.2 Compose files
Compose files are YAML, and indentation and version fields matter. Always run:
docker compose config --quiet
No output means the file is valid. If there is an error, it prints the line and reason. --quiet is non-destructive and fast.
Common mistakes:
- Using a mapping for
environmentlikeVAR: valueinstead of a list. Compose v3 expects a list:
environment:
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypass
- Forgetting to quote strings with special characters, e.g.
$in passwords. Unquoted$VARwill try to expand the host environment. - Using
version: "3.9"but the installed Compose plugin only supports up to 3.8. Remove theversionfield entirely for recent Docker Compose versions; it is optional and can cause a warning.
2.3 Environment variables in CLI
When passing variables to a container, docker run -e or --env-file must use key=value. A trailing space after a comma in --env-file will break parsing. Prefer:
docker run --env-file ./config.env myapp
And inside config.env, one variable per line, no spaces around =.
3. Verification and Diagnostics
After any fix, verify the component works as expected. Use read-only commands first, then logs, then an interactive shell if needed.
3.1 Check container state
docker ps --filter "status=exited" --format "{{.Names}}\t{{.ExitCode}}"
This lists exited containers and their exit codes. A non-zero exit code often points to the reason. Then inspect one:
docker inspect <container> --format '{{.State.ExitCode}} {{.State.Error}} {{.State.OOMKilled}}'
If OOMKilled is true, the container hit a memory limit. Check the limit with docker inspect <container> | grep -i memory, then raise it in the run command (--memory=2g) or in compose (mem_limit: 2g).
3.2 Read logs
docker logs <container> --tail 100 --timestamps
Use --since 10m to see only recent entries. If the container restarts rapidly, follow with docker logs -f <container> to catch the failure before the next restart (the container may be scheduled to restart by a restart policy).
For a Compose service:
docker compose logs <service> --tail 200
3.3 Run an interactive debug shell
Sometimes you need to see the filesystem or test a network connection inside the container. Do not modify the image; run a new shell with the same configuration:
docker run --rm -it --entrypoint sh <image>
This starts a fresh container from the image with an overridden entrypoint. Then you can ls, cat config files, or curl a local endpoint.
For a running container, use docker exec:
docker exec -it <container> sh
Be careful: any changes you make in an exec session are not saved to the image and will be lost when the container restarts. Use this for observation only.
3.4 Network diagnostics
To test connectivity between containers, run a tiny Alpine container with ping or curl:
docker run --rm --network <mynetwork> alpine ping <other-container-name>
If the ping fails, check that both containers are on the same network: docker network inspect <mynetwork> and look at the Containers map. Names are only resolvable on user-defined networks, not on the default bridge.
4. Failure Modes and Recovery
Here are the most common Docker CLI errors, their causes, and fixed recovery steps.
4.1 Cannot connect to the Docker daemon at unix:///var/run/docker.sock
Cause: the Docker daemon is not running, or your user lacks permission to access the socket.
Fix:
- Check if the daemon is running:
systemctl status dockeron Linux, or open Docker Desktop on macOS/Windows. - On Linux, if the daemon is running but you get permission denied, add your user to the
dockergroup:
sudo usermod -aG docker $USER
Log out and back in, or run newgrp docker to refresh group membership without logging out.
- If you use rootless Docker, set the
DOCKER_HOSTenvironment variable to the user socket:export DOCKER_HOST=unix:///run/user/1000/docker.sock.
Verify: docker info should return without error.
4.2 Pull access denied / repository does not exist
Error examples: pull access denied for myimage, repository does not exist or may require 'docker login'.
Fix:
- For public images, ensure the name is correct:
docker pull alpine(notAlpineoralpine:latestif the tag is wrong). - For private registries, log in first:
docker login registry.example.com
Then pull with the full path: docker pull registry.example.com/team/myimage:tag.
- If you are using Docker Desktop and the registry is on your host (e.g.
localhost:5000), you may need to add an insecure registry entry in daemon settings or configure a TLS cert.
Verify: docker pull succeeds and the image appears in docker images.
4.3 Port already in use
Error: docker: Error response from daemon: driver failed programming external connectivity on endpoint ... Bind for 0.0.0.0:8080 failed: port is already allocated.
Fix:
- Find what is using the port on the host:
sudo ss -ltnp | grep 8080orsudo lsof -i :8080. - Stop the conflicting process (if possible) or change the host port:
docker run -p 8081:8080or in compose:
ports:
- "8081:8080"
- If the conflict is with another container, remove or stop that container, or use a dynamic port:
docker run -P(maps container port to a random high host port).
Verify: docker ps shows your container with the chosen host port, and a curl http://localhost:8081 returns the expected response.
4.4 Container exits immediately
Your docker run command started, but docker ps shows no container. docker ps -a shows it exited with code 0 or 1.
Common causes:
- The container's main process finished. For example, a one-shot script needs a foreground process to stay alive.
- The command is missing. If you run
docker run myimageand the image has noCMD, the container exits. - The app crashes due to missing environment variables, configuration, or dependency.
Fix:
- Always run with
-itfor interactive testing:docker run -it myimage shand manually start the app to see errors. - Check logs:
docker logs <container>. - For a service that should stay up, ensure the command is a long-running process like
nginx -g 'daemon off;'ortail -f /dev/nullfor testing. - In compose, set
restart: unless-stoppedto auto-restart after crashes, but still check logs for root cause.
4.5 Can't find file or directory
Errors: no such file or directory when mounting a volume, or inside the container the expected file is missing.
Cause: host path does not exist, or the path inside the container is wrong, or the file is not copied because it's in .dockerignore.
Fix:
- For bind mounts, ensure the host directory exists before
docker run. Docker will create it as root-owned if missing, leading to permission issues. Create it yourself:mkdir -p ./data. - For COPY in a Dockerfile, check
.dockerignoredoes not exclude the file. - For volumes, check if the volume has data:
docker volume inspect myvolumeand look at the mountpoint. You can copy data into the volume by running a one-off container with the volume mounted. - Inside the container, use
lsandpwdto verify the working directory. The default working directory is/unless set withWORKDIRin the Dockerfile or-won the CLI.
5. Common Pitfalls and How to Recover
Even experienced Docker users hit these surprises.
5.1 Editing files inside a container without a volume
You docker exec into a container, modify a config file, restart the container, and the change is gone. Why? The container filesystem is ephemeral and does not persist by default.
Avoid: never make manual changes inside a running container that you expect to survive. Instead, either:
- Build the change into the image via Dockerfile, or
- Mount a volume or bind mount for that file/directory, and edit the file on the host.
If you already made an emergency change and need it to survive until the next deploy, commit the container to a temporary image:
docker commit <container> myapp:hotfix
But treat this as a stopgap, not a workflow. The image lacks the build context and documentation.
5.2 Using latest tag in production
docker pull myapp:latest may get a different version tomorrow, and the deployment breaks.
Recover: always pin versions in compose files and CI/CD. Use specific tags like myapp:1.2.3 or a digest. If you used latest in a running deployment, you can inspect the exact image with docker inspect <container> --format '{{.Image}}', then find the digest and recreate the container with that digest.
5.3 Forgetting to clean up resources
Over time, dangling images, stopped containers, unused networks, and volumes accumulate and fill the disk.
Fix: schedule regular cleanup. Run these manually:
docker container prune # remove stopped containers
docker image prune # remove dangling images
docker network prune # remove unused networks
docker volume prune # remove unused volumes
Or use docker system prune -a to remove all unused resources, but be careful: this deletes all stopped containers, unused networks, and images not used by any container. It does not delete named volumes by default; add --volumes to do so. This is a destructive operation; run it only when you understand the impact.
5.4 Ignoring health checks
A container may be "running" but not ready to serve requests. Docker's HEALTHCHECK instruction in the Dockerfile or healthcheck in compose can mark a container as unhealthy.
Recover: add a health check. Example for a web service:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
Then use docker inspect --format '{{.State.Health.Status}}' <container> to see healthy, unhealthy, or starting. In compose, docker compose ps shows the health status.
5.5 Not using a restart policy in production
If a container dies and nothing restarts it, your service is down until someone manually intervenes.
Add a restart policy:
docker run --restart unless-stopped myapp
Or in compose:
restart: unless-stopped
unless-stopped restarts the container unless you explicitly stopped it. always also restarts after the daemon restarts, but unless-stopped is usually safer because it respects manual maintenance.
6. Operations Checklist
Use this checklist before and after any Docker change in a shared environment.
Before the change
- [ ] Run
docker context lsand confirm you are targeting the correct daemon (default, not a remote prod). - [ ] Record current state:
docker ps,docker images,docker system df,docker compose ps(if applicable). Save output to a file with timestamp. - [ ] Identify the exact resource you will change: image, container, network, volume, or configuration file.
- [ ] Determine the blast radius: is this a single container or a whole stack? What depends on it?
- [ ] Prepare a rollback path: can you revert the config change, redeploy the previous image tag, or restore a volume snapshot?
- [ ] For config file changes, validate syntax first:
docker compose config --quietordockerd --validate.
After the change
- [ ] Run the verification command that proves the fix worked, e.g.
curl http://localhost:8080/healthordocker logs <container> --tail 50shows no errors. - [ ] Check dependent services: do they still connect? Is the network intact?
docker network inspectshows expected containers. - [ ] Monitor for a few minutes:
docker stats <container>shows CPU and memory,docker eventsshows lifecycle changes. - [ ] Update the runbook or incident document with the error, cause, fix, and verification.
- [ ] Schedule a review if the fix is temporary: set a reminder to revisit the issue in, for example, one week or before the next release.
Single accountable owner: in a team context, assign one person (e.g. the on-call engineer or the developer who made the change) to be responsible for completing the checklist and documenting the outcome. For recurring operational tasks, rotate this ownership weekly.
Conclusion
Docker CLI errors are usually caused by a small set of recurring issues: daemon connectivity, image pull failures, port conflicts, exiting containers, and file or volume misconfigurations. The path to recovery is the same each time: observe the state, isolate the failing component, make one surgical change, and verify with a specific command.
Keep this guide handy as a reference for the next error you see. Start with docker version and docker info, then proceed to the matching error section. After the fix, run the verification command and record what you did. That turns an incident into a lesson.
For further reading, explore the official Docker documentation on CLI commands, daemon configuration, and Compose specifications. The more you practice the observe-change-verify loop, the faster you will solve future Docker problems.