Docker Container Keeps Restarting — How to Fix It

Last updated May 24, 2026

TL;DR

A container in a Restarting loop is crashing, getting auto-restarted by Docker, and crashing again. The restart policy isn't the problem — whatever happens between starts is.

Five things to check in order:

  • The exit code (docker inspectState.ExitCode) tells you how it died
  • The logs (docker logs --tail 100 <container>) tell you why
  • Exit 137 = OOM kill (raise memory limit)
  • Exit 139 = segfault (app bug, missing native dep)
  • Exit 0 = process exited cleanly (Docker treats clean exit as "done", --restart always then restarts it forever)

Run docker logs --tail 100 <container> first. Almost every restart loop is solved by reading the actual error the app printed.

What you're seeing

$ docker ps
CONTAINER ID   IMAGE         STATUS                          NAMES
abc123def456   myapp:latest  Restarting (1) 3 seconds ago    myapp

Or from docker ps -a:

CONTAINER ID   STATUS                              NAMES
abc123def456   Restarting (137) 15 seconds ago     myapp

The number in parens is the exit code — it's the single most useful piece of information on the screen.

What's causing this error

A container restarts when:

  1. Its main process exits, and
  2. The container has --restart always, --restart on-failure, or --restart unless-stopped

So "container keeps restarting" really means "the process inside the container keeps exiting." The five real reasons:

  1. App crashes immediately on startup. Missing config, bad env var, syntax error, missing file. The logs almost always say why — most people just don't check them.
  2. App exits cleanly (exit 0). Some images run a one-shot command and exit. With --restart always, Docker dutifully restarts the now-completed task forever.
  3. OOM killed. The container exceeds its memory limit. Linux's OOM killer sends SIGKILL → exit 137.
  4. Missing dependency at runtime. A volume isn't mounted, a network service isn't reachable, a config file isn't where the app expects.
  5. Healthcheck failing. With Swarm or compose restart: on-failure policies, failing healthchecks trigger restarts even when the process itself is alive.

How to fix it

Step 1: Read the logs

docker logs --tail 100 myapp

90% of the time this prints the actual error. Look for stack traces, "permission denied," "connection refused," "no such file or directory," "ENOENT," panic messages.

If logs are empty or <no log>, the process didn't get far enough to write anything — usually means the entrypoint script is broken or the binary doesn't exist.

Step 2: Check the exit code

docker inspect myapp --format='{{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}'

What the common exit codes mean:

Exit codeMeaningLikely cause
0Clean exitProcess completed (one-shot script / cron-style command being restarted by policy)
1General errorApp-level failure; check logs
125Docker itself failedBad docker run flags or daemon issue
126Command not executablePermission issue on entrypoint script
127Command not foundWrong path in CMD/ENTRYPOINT, missing binary
137SIGKILL (often OOM)Memory limit exceeded; OOMKilled: true confirms
139SIGSEGVSegfault — app bug, missing native lib, wrong CPU arch (x86 image on ARM)
143SIGTERMContainer told to stop; usually means docker stop ran during your investigation

Step 3: Stop the restart loop while you debug

The loop makes diagnosis hell — the container disappears between every docker exec. Disable restart:

docker update --restart=no myapp
docker stop myapp

Now you can run it interactively to see what happens:

docker run --rm -it --entrypoint sh myapp:latest
# Inside the container, manually run whatever the CMD was:
# /app/start.sh

This gives you a shell, runs the failing command, and shows you the actual output.

Step 4: Fix by category

Exit 0 + --restart always — the app is finishing its work and Docker restarts it forever:

docker update --restart=on-failure myapp
# Or remove the restart policy entirely:
docker update --restart=no myapp

on-failure only restarts on non-zero exits, leaving clean exits alone.

Exit 137 + OOMKilled: true — memory limit too low:

docker update --memory=1g --memory-swap=1g myapp

Or remove the limit if you set one too aggressively:

docker update --memory=0 myapp

Exit 127 (command not found) — your CMD references a binary that isn't in the image. Usually a copy/paste error in the Dockerfile or wrong path. Run interactively (step 3) and check which <command>.

Healthcheck failing — the process is fine but the healthcheck script is wrong. Check:

docker inspect myapp --format='{{json .State.Health}}' | jq

Either fix the healthcheck command in your Dockerfile, or remove it temporarily:

# docker-compose.yml
services:
  myapp:
    healthcheck:
      disable: true

Common edge cases

SituationWhat's actually wrong
Status shows Restarting (0)App is exiting cleanly. --restart always is restarting a successful one-shot command. Switch to --restart on-failure or remove the policy.
Exit 137 but OOMKilled: falseNot OOM — something else sent SIGKILL. Usually docker stop with a slow shutdown that timed out. Lengthen the stop timeout or fix the app's signal handling.
Logs show "permission denied" on a mounted volumeContainer user (often UID 1000) doesn't match the volume's file ownership. Either chown -R 1000:1000 the volume contents, or run the container as the matching user.
Container works locally, restart loops on the serverDifferent CPU arch — common when an Apple Silicon Mac builds an ARM image and pushes to an x86 server. Build with --platform linux/amd64.
Restarts only when scaled to multiple instancesPort conflict between instances, or stateful storage that doesn't support concurrent writers (SQLite over NFS, etc.)
Healthcheck killing perfectly fine containerHealthcheck start_period too short — app takes longer to warm up than the grace period. Increase start_period in Dockerfile or compose.
Restarts only at certain times of dayCron job inside container exits, or scheduled task triggers OOM. Check docker inspect for restart timestamps and correlate.

Related errors