Why Do Docker Containers Fail to Start? Common Causes and Troubleshooting Commands
This guide walks operators through the most frequent reasons Docker containers fail to start—such as image issues, misconfigurations, resource limits, permission problems, network errors, and volume mishaps—and provides a step‑by‑step command checklist to diagnose and fix each scenario.
Background
Docker container startup failures are a common operational problem. Containers can fail for many reasons, including missing or corrupted images, configuration errors, insufficient resources, network connectivity issues, permission restrictions, health‑check failures, or unavailable dependent services. After a container exits, docker ps without -a does not show it, and logs may be sparse, making troubleshooting harder.
Troubleshooting Process
When a container fails to start, follow these steps in order:
Step 1: Verify container status
└─ docker ps -a | grep <container-name>
Step 2: View container exit information
└─ docker logs <container-id>
└─ docker inspect <container-id>
Step 3: Identify root cause
├─ Image problems (missing, corrupted, wrong tag)
├─ Configuration problems (port conflict, missing env vars, wrong command)
├─ Resource problems (memory, disk space)
├─ Permission problems (SELinux/AppArmor, user rights, mount rights)
├─ Network problems (DNS, port mapping, overlay network)
├─ Dependency problems (service not ready)
└─ Health‑check failures (restart loops)
Step 4: Fix and verify
└─ docker run / docker startStep 1 – Confirm Container Status
Basic Status Check
# List all containers (including exited)
docker ps -a
# Filter by name
docker ps -a | grep <container-name>
# Formatted output for clarity
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Image}}"Typical Status values: Exited (1) 5 minutes ago: exited with code 1 Created: created but not started Up 2 hours: running normally Restarting (1) (starting): repeatedly crashing
Quick Exit‑Code Inspection
# One‑line status, exit code, OOM flag, and command
docker inspect <container-id> --format='{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}} {{.Config.Cmd}}'
# Full state JSON (use jq for parsing)
docker inspect <container-id> | jq '.State'Step 2 – View Container Logs
docker logs
# Standard output + error
docker logs <container-id>
# Follow live output
docker logs -f <container-id>
# Last 100 lines
docker logs --tail 100 <container-id>
# Include timestamps
docker logs --timestamps <container-id>
# Logs since a specific time
docker logs --since "2024-01-15T10:00:00" <container-id>
docker logs --since 30m <container-id>
# Filter for errors
docker logs <container-id> 2>&1 | grep -i errorWhy Logs May Be Empty
Application does not write to stdout/stderr : CMD/ENTRYPOINT redirects output to a file.
Wrong log driver : containers may use json-file, syslog, fluentd, awslogs, etc.
Log rotation removed the file .
# Check which log driver is configured
docker inspect <container-id> --format='{{.HostConfig.LogConfig.Type}}'
# If json‑file, view the raw log file
cat /var/lib/docker/containers/<container-id>/*-json.log | tail -100Step 3 – Inspect Container Details
docker inspectreveals every configuration detail from creation to runtime.
# Full JSON output (very large)
docker inspect <container-id>
# Extract specific sections with jq
docker inspect <container-id> --format='{{json .State}}' | jq .
docker inspect <container-id> --format='{{json .Config}}' | jq .
docker inspect <container-id> --format='{{json .HostConfig}}' | jq .
# Common fields to display
docker inspect <container-id> --format='
State: {{.State.Status}}
ExitCode: {{.State.ExitCode}}
OOMKilled: {{.State.OOMKilled}}
Error: {{.State.Error}}
StartedAt: {{.State.StartedAt}}
FinishedAt: {{.State.FinishedAt}}
Path: {{.Path}}
Args: {{.Args}}
WorkingDir: {{.Config.WorkingDir}}
Cmd: {{.Config.Cmd}}
Entrypoint: {{.Config.Entrypoint}}
Env: {{range .Config.Env}}{{.}} {{end}}'Common Exit Codes
0 : Normal exit – process completed.
1 : General error – application‑level misconfiguration.
125 : Docker daemon error – e.g., memory limit exceeded.
126 : Command not executable – permission or path issue for CMD/ENTRYPOINT.
127 : Command not found – missing binary or PATH problem.
137 : SIGKILL (OOM) – out‑of‑memory kill.
139 : SIGSEGV – segmentation fault.
143 : SIGTERM – graceful stop via docker stop.
Step 4 – Categorized Diagnosis
4.1 Image Problems
Typical error messages:
Error: image nginx:1.24 not found
Layer already exists
docker: Error response from daemon: manifest for xxx not foundKey commands:
# List local images
docker images
# Inspect image details
docker inspect nginx:1.24
# Pull the image
docker pull nginx:1.24
# Verify tag existence
docker manifest inspect nginx:1.24
# Remove dangling images
docker image prune -fCommon scenarios:
Tag is latest but not updated : image built but not pushed or retagged.
Wrong registry address : private registry URL typo.
Image deleted : another machine overwrote the tag; local digest is stale.
Cross‑architecture pull : pulling an x86 image on ARM leads to manifest incompatibility.
# Check image architecture
docker inspect <image> | grep Architecture
# Show digests
docker images --digestsFixes:
# Re‑pull the correct image
docker pull <image>:<tag>
# For private registries
docker login registry.example.com
docker pull registry.example.com/my-app:v1.2.3
# If digest changed, roll back to the old digest
docker images --digests | grep <image>
docker run --rm <image>@sha256:xxxxdigestxxxx4.2 Configuration Problems
Port Conflict
docker: Error response from daemon: Ports are not available: bind address port already in use.Check which process occupies the port:
# Linux
ss -tlnp | grep :80
netstat -tlnp | grep :80
# macOS (no ss/netstat)
lsof -i :80
# Verify Docker daemon listening ports
ps aux | grep dockerdFixes:
# Use a different host port
docker run -p 8080:80 nginx
# Stop the service using the port
systemctl stop nginx
kill $(lsof -t i:80)
# Ensure no other container uses the same port
docker ps --format "{{.Names}} {{.Ports}}"Missing or Wrong Environment Variables
FATAL: Required environment variable DATABASE_URL is not setInspect environment variables:
# Show env vars from the container
docker inspect <container-id> --format='{{range .Config.Env}}{{.}} {{end}}'
# Compare with expected values
docker inspect <container-id> | jq '.Config.Env'
# If using an .env file, verify its presence
cat .envFixes:
# Pass the variable at run time
docker run -e "DATABASE_URL=postgres://user:pass@host:5432/db" my-app
# Docker‑compose syntax
docker-compose run -e "DATABASE_URL=..." appIncorrect Startup Command
# Exit code 127 or 126 indicates command not found
docker: Error response from daemon: OCI runtime create failed: ...Check CMD and ENTRYPOINT:
# Show CMD
docker inspect <container-id> --format='{{.Config.Cmd}}'
# Show ENTRYPOINT
docker inspect <container-id> --format='{{.Config.Entrypoint}}'
# Test the command manually
docker run --rm <image> <cmd> <args>
# Open a shell inside the image
docker run --rm -it <image> shCommon mistakes:
ENTRYPOINT and CMD order reversed.
Using shell form (e.g., CMD python app.py) which interferes with signal handling.
Path errors when WORKDIR differs from the binary location.
# Correct JSON form
ENTRYPOINT ["python", "app.py"]
CMD ["--help"]
# Ensure the binary path matches WORKDIR
CMD ["/app/app.py"]4.3 Resource Problems
Out‑of‑Memory (OOM)
# docker logs may be empty
# docker inspect shows OOMKilled: true
# Exit code 137 or 143Check OOM status and host memory:
# OOM flag
docker inspect <container-id> | grep OOMKilled
# Host memory
free -h
# cgroup limits
cat /sys/fs/cgroup/memory/docker/<container-id>/memory.limit_in_bytes
cat /sys/fs/cgroup/memory/docker/<container-id>/memory.usage_in_bytes
# Kernel OOM messages
dmesg | grep -i oom | tail -20
journalctl | grep -i oom | tail -20Fixes:
# Increase memory limit
docker run --memory=1g my-app
# Remove limit (not recommended for production)
docker run --memory="" my-app
# Investigate application memory leaks
docker stats --no-streamDisk Space Exhaustion
no space left on device
Error: disk quota exceeded
docker: writing tmp: no space left on deviceCheck disk usage:
# Host filesystem
df -h
df -h /var/lib/docker
# Docker resource usage
docker system df
docker ps -s | sort -k3 -rh | head
# Clean up
docker system prune -af
docker builder prune -afFixes:
# Remove unused resources
docker system prune -a --volumes
# Delete container logs
> /var/lib/docker/containers/<container-id>/*-json.log
# Configure log rotation (daemon.json)
{
"log-driver": "json-file",
"log-opts": {"max-size": "100m", "max-file": "3"}
}4.4 Permission Problems
SELinux / AppArmor
permission denied: /var/www/html
docker: Error response from daemon: OCI runtime create failed: ... operation not permittedCheck SELinux/AppArmor status:
# SELinux (CentOS/RHEL)
getenforce
ausearch -m AVC -ts recent
# AppArmor (Ubuntu)
aa-status
apparmor_parser -r /etc/apparmor.d/*
# Privileged mode
docker inspect <container-id> | grep PrivilegedFixes:
# Temporarily disable SELinux (not for production)
setenforce 0
# Run privileged (not recommended)
docker run --privileged my-app
# Proper SELinux label
docker run -v /data:/data:Z my-app
# Disable AppArmor profile for testing
docker run --security-opt apparmor=unconfined my-appFilesystem Permissions
cannot create directory '/var/log/xxx': Permission denied
read-only file systemInspect read‑only flag and mount permissions:
# Check read‑only rootfs
docker inspect <container-id> | grep ReadonlyRootfs
# Inspect volume permissions
ls -la /var/lib/docker/volumes/<volume-name>/_data
# Check container user
docker inspect <container-id> | grep -E "User|WorkingDir"Fixes:
# Set correct workdir and ownership in Dockerfile
WORKDIR /app
RUN chown -R appuser:appuser /app
# Run as non‑root user
docker run -u appuser my-app
# If root is required, use privileged mode
docker run -u root --privileged my-app4.5 Network Problems
Dependent Service Not Ready
# Container starts but cannot connect to database
dial tcp 192.168.1.21:5432: connection refused
Container may be in Restarting stateCheck connectivity from the container:
# Test TCP port
docker exec <app-container-id> nc -zv db-host 5432
# Test HTTP endpoint
docker exec <app-container-id> curl -v http://api-host:8080/health
# DNS resolution
docker exec <app-container-id> nslookup db-host
cat /etc/resolv.conf
# Inspect network settings
docker inspect <container-id> | grep -A 10 "Networks"Solutions:
# Use depends_on for start order (docker‑compose)
services:
app:
image: my-app
depends_on:
- db
- redis
db:
image: postgres:15
redis:
image: redis:alpine
# Add healthcheck with condition
services:
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
app:
image: my-app
depends_on:
db:
condition: service_healthy
# Application‑level retry (Python example)
import time, psycopg2
def connect_with_retry(max_retries=10, delay=5):
for i in range(max_retries):
try:
return psycopg2.connect(os.environ['DATABASE_URL'])
except psycopg2.OperationalError as e:
print(f"Attempt {i+1} failed: {e}")
time.sleep(delay)
raise Exception("Could not connect to database after retries")Health‑check Failure Causing Restart Loop
# docker ps shows constantly restarting
# docker inspect shows Health status not healthy
# Application logs look fineInspect health‑check configuration and logs:
# Show health config
docker inspect <container-id> | grep -A 10 "Health"
# Show health JSON
docker inspect <container-id> --format='{{json .State.Health}}' | jq .
# View health‑check log entries
docker inspect <container-id> | grep -A 5 "Log"Typical fix:
# Define a proper healthcheck in docker‑compose.yml
services:
app:
image: my-app
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s4.6 Volume Problems
Host Directory Does Not Exist
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /data/logs.Check host directory existence and permissions:
# Verify directory
ls -la /data/logs
# Check permissions
ls -la /data
# List Docker volumes
docker volume ls
docker volume inspect <volume-name>Fixes:
# Create the directory
mkdir -p /data/logs
chmod 755 /data/logs
# Use a named volume (Docker creates it automatically)
docker volume create my-dataVolume Overwrites Container Data
Explanation: a bind mount completely masks the container’s target directory. If the host path contains data, the container’s original files become invisible.
Fixes:
# Avoid bind‑mounting over important container directories; use an empty directory instead.
# Use a named volume to share data without overwriting.
services:
app:
volumes:
- app_data:/var/lib/app
volumes:
app_data:
driver: localCommon Troubleshooting Commands (Quick Reference)
# Container status
docker ps -a
docker ps -a | grep <name>
# Logs
docker logs <id>
docker logs -f <id>
docker logs --tail 100 <id>
docker logs --timestamps <id>
# Detailed info
docker inspect <id>
docker inspect <id> --format='{{.State.Status}}'
docker inspect <id> | jq '.State'
# Images
docker images
docker pull <image>:<tag>
docker rmi <image-id>
# Networks
docker network ls
docker network inspect <network-name>
docker exec <id> cat /etc/resolv.conf
# Resource usage
docker stats --no-stream
df -h
docker system df
# Cleanup
docker system prune -af
docker image prune -af
docker builder prune -af
docker container pruneSummary
When a Docker container fails to start, the most effective first steps are to examine docker logs and docker inspect. These commands reveal exit codes, OOM flags, configuration errors, and health‑check status, solving the majority of issues. If the logs are inconclusive, use docker run --rm -it <image> sh to enter the image and reproduce the startup process manually.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Raymond Ops
Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
