Docker Troubleshooting: Solving the 20 Most Common Problems
Docker is reliable, but it is also complex. When something goes wrong, the error messages are not always helpful, and the root cause can hide in any of a dozen different layers: the daemon, the image, the container configuration, networking, storage, or the application itself. This guide covers the 20 most common Docker problems and provides direct, actionable solutions for each one.
1. Container Exits Immediately After Starting
The most common Docker problem. The container starts and immediately exits with code 0 or 1.
# Check the exit code
docker ps -a --filter "name=mycontainer"
# STATUS: Exited (1) 5 seconds ago
# Read the logs
docker logs mycontainer
# If the container exits too fast for logs:
docker run -it --entrypoint sh myimage
# Now you're inside and can debug
Common causes:
- Exit code 0: The main process completed (not a daemon). Make sure your CMD runs a foreground process, not a background one.
- Exit code 1: Application error. Check logs for the specific error.
- Exit code 127: Command not found. The binary in CMD/ENTRYPOINT does not exist in the image.
- Exit code 126: Permission denied on the entry point binary.
# Common fix: Ensure the process runs in the foreground
# Wrong (nginx daemonizes and container exits):
CMD ["nginx"]
# Right (nginx stays in foreground):
CMD ["nginx", "-g", "daemon off;"]
2. Port Conflicts
# Error: bind: address already in use
docker run -p 80:80 nginx
# Error response from daemon: driver failed programming external connectivity:
# Bind for 0.0.0.0:80 failed: port is already allocated
# Find what's using the port
sudo lsof -i :80
# or
sudo ss -tlnp | grep :80
# Solutions:
# 1. Use a different host port
docker run -p 8080:80 nginx
# 2. Stop the conflicting service
sudo systemctl stop apache2
# 3. Kill the conflicting container
docker ps --filter "publish=80" -q | xargs docker stop
3. Disk Space Full
# Error: no space left on device
# Check Docker disk usage
docker system df
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 45 3 12.5GB 10.2GB (81%)
# Containers 52 3 1.2GB 800MB (66%)
# Local Volumes 23 5 8.3GB 5.1GB (61%)
# Build Cache 102 4.5GB 4.5GB (100%)
# Quick fix: Remove everything unused
docker system prune -a --volumes
# WARNING! This will remove all stopped containers, unused networks,
# unused images, unused volumes, and build cache.
# More targeted cleanup:
docker container prune # Remove stopped containers
docker image prune -a # Remove unused images
docker volume prune # Remove unused volumes
docker builder prune # Remove build cache
# Find the biggest offenders
docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -rh | head -20
4. DNS Resolution Failures Inside Containers
# Container can't resolve hostnames
docker run --rm alpine nslookup google.com
# ;; connection timed out; no servers could be reached
# Check Docker's DNS configuration
docker run --rm alpine cat /etc/resolv.conf
# Solution 1: Specify DNS servers explicitly
docker run --dns 8.8.8.8 --dns 8.8.4.4 --rm alpine nslookup google.com
# Solution 2: Configure Docker daemon DNS
# /etc/docker/daemon.json
{
"dns": ["8.8.8.8", "8.8.4.4"]
}
sudo systemctl restart docker
# Solution 3: Fix the host's resolv.conf (common on Ubuntu with systemd-resolved)
# Docker copies the host's /etc/resolv.conf, which may contain 127.0.0.53
# This address is unreachable from inside containers
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart docker
5. Permission Denied Errors
# "Got permission denied while trying to connect to the Docker daemon socket"
# Your user is not in the docker group
# Fix:
sudo usermod -aG docker $USER
# Log out and log back in (or: newgrp docker)
# "permission denied" inside a container accessing mounted volumes
docker run -v /host/data:/data myapp
# Error: Permission denied when writing to /data
# Check the user inside the container
docker run --rm myapp id
# uid=1000(app) gid=1000(app)
# Solutions:
# 1. Match the container user to the host user
docker run -u $(id -u):$(id -g) -v /host/data:/data myapp
# 2. Fix host directory permissions
chmod 777 /host/data # Quick but insecure
chown 1000:1000 /host/data # Match container UID
# 3. Use named volumes instead (Docker manages permissions)
docker volume create mydata
docker run -v mydata:/data myapp
6. Image Pull Failures
# "Error response from daemon: toomanyrequests: You have reached your pull rate limit"
# Docker Hub rate limits: 100 pulls/6h (anonymous), 200/6h (authenticated)
# Solution 1: Log in to Docker Hub
docker login
# Solution 2: Set up a pull-through cache
# See our private registry guide for details
# "Error response from daemon: manifest unknown"
# Wrong tag or image name
docker pull nginx:wrong-tag # This tag doesn't exist
docker pull nginx:1.25-alpine # Use the correct tag
# "Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: no such host"
# Network/DNS issue on the host
# Check your internet connection and DNS
nslookup registry-1.docker.io
ping registry-1.docker.io
# "x509: certificate signed by unknown authority"
# Using a private registry with self-signed certs
# Copy the CA cert to:
sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000
sudo cp ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt
7. Container Networking Issues
# Containers on the same network can't communicate
# Verify they're on the same network
docker network inspect my-network | jq '.[0].Containers'
# Test connectivity between containers
docker exec container-a ping container-b
docker exec container-a nslookup container-b
# Common cause: using the default bridge network
# The default bridge does NOT support DNS resolution between containers
# Solution: Create and use a custom network
docker network create my-app-net
docker run --network my-app-net --name web nginx
docker run --network my-app-net --name app myapp
# Now 'web' and 'app' can resolve each other by name
# Container can't reach the internet
docker run --rm alpine ping -c 3 8.8.8.8
# If this fails, check IP forwarding:
sysctl net.ipv4.ip_forward
# Should be 1. If not:
sudo sysctl -w net.ipv4.ip_forward=1
# Check iptables rules
sudo iptables -t nat -L -n | grep MASQUERADE
8. OOM (Out of Memory) Kills
# Container is killed unexpectedly
docker inspect mycontainer | jq '.[0].State.OOMKilled'
# true
# Check kernel OOM messages
dmesg | grep -i "oom\|out of memory" | tail -20
# Solution 1: Increase memory limit
docker run -m 512m myapp
# In Compose:
# deploy:
# resources:
# limits:
# memory: 512M
# Solution 2: Fix the memory leak in your application
# Monitor memory usage over time:
docker stats mycontainer
# Solution 3: Set memory reservation (soft limit) and limit (hard limit)
docker run -m 512m --memory-reservation 256m myapp
9. Zombie/Defunct Processes
# PID 1 in a container doesn't reap child processes
docker exec mycontainer ps aux
# PID USER STAT COMMAND
# 1 root Ss node server.js
# 15 root Z [worker]
# 16 root Z [worker]
# Solution 1: Use tini as an init process
# In Dockerfile:
RUN apk add --no-cache tini
ENTRYPOINT ["tini", "--"]
CMD ["node", "server.js"]
# Solution 2: Use Docker's built-in init
docker run --init myapp
# Solution 3: In Compose
services:
app:
image: myapp
init: true
10. Slow Docker Builds
# Builds taking too long
# Solution 1: Check your .dockerignore
# Missing .dockerignore means Docker sends EVERYTHING to the daemon
cat .dockerignore
# Add these at minimum:
# .git
# node_modules
# __pycache__
# *.pyc
# .env
# dist/
# build/
# Check context size
docker build . 2>&1 | head -5
# "Sending build context to Docker daemon 2.15GB" <- Way too big!
# Solution 2: Order Dockerfile layers correctly
# Put rarely-changing instructions first:
COPY package.json package-lock.json ./ # Changes rarely
RUN npm ci # Cached if package.json unchanged
COPY . . # Changes often (last!)
RUN npm run build
# Solution 3: Use BuildKit cache mounts
RUN --mount=type=cache,target=/root/.npm npm ci
# Solution 4: Use multi-stage builds to avoid installing dev dependencies
FROM node:20-alpine AS builder
COPY . .
RUN npm ci && npm run build
FROM node:20-alpine
COPY --from=builder /app/dist /app/dist
COPY package*.json ./
RUN npm ci --production
11. Volume Mount Not Reflecting Changes
# Bind mount changes aren't visible inside the container
# On macOS/Windows with Docker Desktop:
# File watching may not work due to filesystem event translation
# Solution: Use Docker Compose polling
services:
app:
volumes:
- ./src:/app/src
environment:
- CHOKIDAR_USEPOLLING=true # For Node.js
- WATCHPACK_POLLING=true # For Webpack
# On Linux:
# Check that the path is correct and exists
ls -la /host/path/to/mount
docker exec mycontainer ls -la /container/path
# Check if SELinux is blocking access
# Add :z (shared) or :Z (private) suffix
docker run -v /host/data:/data:z myapp
# Named volume data persists even after container removal
# but a new container gets the OLD data, not a fresh copy:
docker volume inspect mydata
12. Container Logs Consuming Disk Space
# Find large log files
sudo du -sh /var/lib/docker/containers/*/\*-json.log | sort -rh | head
# Truncate a log file (immediate fix)
sudo truncate -s 0 /var/lib/docker/containers/CONTAINER_ID/*-json.log
# Permanent fix: Configure log rotation
# /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
sudo systemctl restart docker
# Per-container in Compose:
services:
app:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
13. Docker Compose Services Not Communicating
# Services in docker-compose.yml can't reach each other
# Make sure you're using service names, not localhost
# Wrong:
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
# Right:
DATABASE_URL=postgres://user:pass@db:5432/mydb
# Check that services are on the same network
docker compose ps
docker network inspect myapp_default
# Wait for dependencies (depends_on only waits for container start, not readiness)
services:
app:
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
14. "Cannot Stop Container" or Docker Daemon Hang
# Container won't stop (docker stop hangs)
# Force kill after timeout
docker kill mycontainer
# If docker kill also hangs, restart the daemon
sudo systemctl restart docker
# Nuclear option: kill the container process directly
# Find the PID
docker inspect mycontainer | jq '.[0].State.Pid'
sudo kill -9 <PID>
# If the daemon itself is hung
sudo systemctl restart docker
# If systemctl restart hangs, force kill dockerd
sudo kill -9 $(pidof dockerd)
sudo systemctl start docker
15. Build Context Too Large
# "Sending build context to Docker daemon 5.24GB"
# Create or fix .dockerignore
cat > .dockerignore <<'EOF'
.git
node_modules
__pycache__
*.pyc
.env*
dist/
build/
*.tar.gz
*.log
.DS_Store
coverage/
.pytest_cache/
EOF
# Verify what's being sent
# Use a trick to see the context size:
docker build --no-cache -t test -f - . <<<"FROM scratch" 2>&1 | head -1
16. Container Can't Write to Mounted Volume (Read-Only Filesystem)
# "Read-only file system" error inside container
# Check if the volume is mounted read-only
docker inspect mycontainer | jq '.[0].Mounts'
# Look for "Mode": "ro"
# Check if the image uses a read-only root filesystem
docker inspect mycontainer | jq '.[0].HostConfig.ReadonlyRootfs'
# If using --read-only, add tmpfs mounts for writable directories
docker run --read-only \
--tmpfs /tmp \
--tmpfs /run \
-v mydata:/app/data \
myapp
17. Docker Network IP Address Conflicts
# Docker networks conflicting with your LAN or VPN
# Check current Docker networks
docker network ls
docker network inspect bridge | jq '.[0].IPAM'
# Configure custom address pools
# /etc/docker/daemon.json
{
"default-address-pools": [
{"base": "10.200.0.0/16", "size": 24}
],
"bip": "10.200.0.1/24"
}
sudo systemctl restart docker
# Per-network configuration in Compose
networks:
mynet:
ipam:
config:
- subnet: 10.201.0.0/24
18. Image Layers Not Caching
# Docker keeps rebuilding layers that should be cached
# Ensure your Dockerfile has stable layers first
# Each COPY/ADD invalidates the cache for all subsequent layers
# Use .dockerignore to prevent irrelevant file changes from busting cache
echo "*.log" >> .dockerignore
# Copy dependency files first, install, then copy source
COPY go.mod go.sum ./
RUN go mod download
# Only source changes invalidate from here:
COPY . .
RUN go build -o /app
# Don't use --no-cache unless you really need it
docker build -t myapp . # Uses cache
docker build --no-cache -t myapp . # Never use this in CI unless necessary
19. "Exec Format Error" When Running Container
# "exec format error" when starting a container
# This means the binary architecture doesn't match the host
# Common when pulling ARM images on x86 or vice versa
# Check image architecture
docker inspect --format '{{.Architecture}}' myimage
# If it says "arm64" but you're on "amd64", that's the problem
# Solution 1: Pull the correct architecture
docker pull --platform linux/amd64 myimage
# Solution 2: Install QEMU for cross-architecture support
docker run --privileged --rm tonistiigi/binfmt --install all
# Solution 3: Build for the correct architecture
docker buildx build --platform linux/amd64 -t myimage .
20. Docker Compose "Orphan Containers" Warning
# "Found orphan containers for this project"
# Happens when you remove or rename services in docker-compose.yml
# Remove orphans during up
docker compose up -d --remove-orphans
# Or remove them explicitly
docker compose down --remove-orphans
General Debugging Toolkit
# The essential Docker debugging commands
# System-wide information
docker info
docker system df
docker system events --since 1h
# Container debugging
docker logs mycontainer --tail 100 --follow
docker inspect mycontainer
docker stats mycontainer
docker top mycontainer
docker exec -it mycontainer sh
# Network debugging
docker network inspect bridge
docker exec mycontainer nslookup other-service
docker exec mycontainer ping other-service
# Daemon logs
journalctl -u docker.service --since "1 hour ago"
For ongoing Docker management and troubleshooting, tools like usulnet provide a visual interface for inspecting container logs, resource usage, and network configuration across multiple hosts—making it faster to identify and resolve issues than switching between terminal sessions.