Why Is My Docker Container Restarting Continuously In A Loop?

Your Docker container keeps restarting, and you have no idea why. You run docker ps, and the status column shows “Restarting” over and over again.

The container looks alive for a few seconds, then vanishes, then comes back. This endless cycle is frustrating, and it can flood your logs, waste CPU, and hide the real problem underneath.

The good news is simple. A restart loop always has a cause, and that cause leaves clues. Docker records exit codes, restart counts, and log output every single time the container dies. Once you learn how to read these signals, the mystery disappears fast.

Key Takeaways

  • A restart loop happens when your main process keeps exiting. Docker sees the process die, follows your restart policy, and starts the container again. This repeats forever until you fix the root cause.
  • The exit code is your single best clue. Exit code 137 means out of memory. Exit code 1 means an app error. Exit codes 126 and 127 mean a bad command or missing file. Always check this first.
  • Logs tell the real story. Run docker logs --tail 100 <container> to read the last output before each crash. Stack traces and connection errors show up here.
  • You can freeze the loop to inspect it. Use docker update --restart=no <container> to stop the container from restarting. This gives you time to look around calmly.
  • Restart policies are a safety net, not a fix. A container that restarts again and again is broken. Fix the app, the config, or the resources instead of relying on restart: always.
  • Most loops come from six causes: memory limits, app crashes, missing dependencies, wrong commands, bad health checks, or a process that exits too early.

What Does A Docker Restart Loop Actually Mean?

A restart loop is not Docker healing itself. It is a crash cycle in disguise. Every container runs one main process in the foreground. When that process exits or gets killed, the container stops too. Docker then checks your restart policy and decides whether to start a new instance.

If your policy is set to always, unless-stopped, or on-failure, Docker brings the container back. But if the process crashes again right away, the cycle repeats. Docker increments a value called RestartCount every single time this happens. This number keeps climbing as long as the loop is active.

The tricky part is timing. The container may look “running” for two or three seconds before it dies again. If you only check whether the process exists, you might miss the failure completely. That is why you need to watch the restart count and exit code, not just the status.

How To Stop The Loop So You Can Inspect It

The first real step is to pause the chaos. A container that restarts every second is almost impossible to inspect. Each time you try to open a shell, you get an error like “Container is restarting, wait until the container is running.” You need to break this cycle first.

Run this command to disable the restart policy on the live container:

docker update --restart=no <container_id>

Now the container will stop the next time it crashes and stay stopped. This gives you a calm, frozen state to work with. You can then read logs, check the filesystem, and inspect the config without the container disappearing on you.

Pros: This method is fast, non destructive, and reversible. It does not delete any data. Cons: It only changes the running container, not your compose file or image. Once you fix the issue, you must restore the policy yourself with another docker update command or a fresh deploy.

Check The Exit Code First Because It Reveals The Cause

The exit code is the most powerful clue you have. It tells you how the process died, which points you straight at the cause. Skip this step, and you will waste hours guessing. Read it first, every time.

Run this single command to see the restart count, exit code, and memory status together:

docker inspect --format '{{.RestartCount}} {{.State.ExitCode}} {{.State.OOMKilled}}' <container_id>

Here is what the common codes mean. Exit code 137 means SIGKILL, usually an out of memory kill. Exit code 139 means a segfault, a native crash. Exit code 143 means SIGTERM, often a failed health check. Exit code 1 is a generic app error, like a missing config file or a dead dependency. Codes 126 and 127 mean the command is not executable or not found.

Pros: This is the fastest diagnosis tool in Docker. One command narrows down the problem instantly. Cons: The code alone does not give full detail. You still need to read logs to find the exact line that failed.

Read The Container Logs To Find The Real Error

Once you know the exit code, the logs fill in the story. The logs show the exact output your app printed right before it died. Stack traces, connection refused errors, and “out of memory” messages all appear here. This is where the truth lives.

Use this command to read the last 100 lines safely:

docker logs --tail 100 <container_id>

The --tail flag matters more than you think. A crashing container in a loop can generate gigabytes of log data. Loading all of it can freeze your terminal. The tail limit keeps things fast and readable.

Look for patterns. A line like “connection refused” points to a missing database. A Python or Java stack trace points to a code bug. A “permission denied” message points to a file ownership issue. The last few lines before each crash almost always name the problem directly.

Pros: Logs give you the actual error message, not just a code. They work for any language or framework. Cons: If the app does not log to stdout or stderr, you may see nothing. Some apps write logs to files inside the container instead, which Docker cannot capture this way.

Fix Memory Problems When You See Exit Code 137

Exit code 137 with OOMKilled set to true is one of the most common causes. It means your container tried to use more memory than its limit allowed, so the kernel killed it. Docker then restarts it, it hits the limit again, and the loop begins.

First, confirm the issue. Run docker stats --no-stream <container_id> to see memory usage against the limit. If usage sits near 100 percent right before the crash, memory is your problem.

To stop the loop quickly, raise the limit on the fly:

docker update --memory 1g <container_id>

This is a temporary fix, not a permanent one. After the loop stops, find out why the app needs so much memory. It might be a real leak, or the limit might simply be too low. For Java apps, set the heap to about 75 percent of the container limit so native memory has room.

Pros: Raising the limit stops the crash instantly and buys you time to investigate. Cons: It hides a possible memory leak. If the app truly leaks memory, a bigger limit only delays the next crash. You must still find the root cause.

Solve Application Crashes And Segfaults

Sometimes the app itself is broken. Exit code 1 means a generic application error, and exit code 139 means a segfault in native code. These are not Docker problems. They are problems inside your program or its data.

Start by capturing the full error from the logs. For exit code 1, look for an unhandled exception, a missing environment variable, or a config file the app could not find. These are the most common reasons an app exits on its own.

For exit code 139, the issue is deeper. A segfault often comes from incompatible native libraries, a corrupt input file, or a binary built for the wrong architecture. Running an x86 image on an ARM machine, like an Apple Silicon Mac, is a classic cause of this.

To debug, override the entrypoint and open a shell instead of running the app:

docker run -it --entrypoint /bin/sh <image>

Now you can run the command manually and watch it fail in real time.

Pros: Manual debugging shows you the exact crash point and lets you test fixes live. Cons: It needs some knowledge of the app and its language. A pure config issue is easy, but a native segfault can take real effort to trace.

Handle Missing Dependencies And Startup Order Issues

Many containers crash because something they need is not ready yet. If your app starts before its database or API is reachable, it exits immediately with an error. Docker restarts it, the dependency is still not ready, and the loop continues.

The logs make this clear. You will see messages like “connection refused,” “could not connect to host,” or DNS errors. These all mean your container could not reach a service it depends on.

The wrong fix is to rely on restart policies to keep retrying until the dependency wakes up. This wastes resources and pollutes your logs. The better fix is to control startup order explicitly. In Docker Compose, use depends_on with a health condition so the app waits for the database to be healthy first.

You can also add a small wait script inside your container that checks the dependency before launching the app. Tools that poll a host and port until it responds work well for this.

Pros: Explicit ordering removes the loop entirely and makes your stack predictable. Cons: It adds a little complexity to your compose file or startup script. You must define health checks for the dependencies too.

Fix Misconfiguration With Exit Codes 126 And 127

Exit codes 126 and 127 point straight at a command problem. Code 127 means “command not found,” and code 126 means “command found but not executable.” These almost always come from a broken entrypoint, a missing file, or a permission issue.

This often happens after an image update. A new tag may change the binary path, or a script may lose its execute permission. The MediaWiki restart loop case that many users hit was caused by exactly this kind of issue, with a 127 status repeating forever.

Check what your container is actually trying to run:

docker inspect --format '{{.Config.Entrypoint}} {{.Config.Cmd}}' <container_id>

Confirm the file exists inside the image and has execute permission. If you copied a script in your Dockerfile, add RUN chmod +x /path/to/script.sh to make it runnable. A single missing chmod line causes countless restart loops.

Pros: These codes are very specific, so the fix is usually quick and clear. Cons: If you did not build the image yourself, you may need to inspect its layers or contact the maintainer to find the broken path.

Stop Health Checks From Killing Your Container Too Early

A health check can cause a restart loop all by itself. If the check runs before your app finishes starting, it marks the container as unhealthy. An orchestrator or autoheal tool then sends SIGTERM, and you see exit code 143 followed by a restart.

The usual culprit is a start_period that is too short. Some apps need thirty seconds or more to boot, but a default health check probes them after just a few seconds. The app is fine; it just needs more time.

Fix this by giving the app room to start. In your Compose file, set a realistic start period:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 60s

Also confirm the health check command itself is correct. A typo in the URL or a missing curl binary inside the image will fail every check.

Pros: A well tuned health check catches real failures while letting slow apps start. Cons: Plain Docker does not restart unhealthy containers on its own. You need an extra tool or an orchestrator to act on the health status, which adds setup.

Make Sure Your Main Process Runs In The Foreground

This cause trips up many beginners. A container only stays alive while its main process runs in the foreground. If your command runs and finishes, or runs as a background daemon, the container exits at once, and your restart policy starts the loop.

A common mistake is running a service in the background. For example, starting Nginx with a command that returns immediately leaves the container with nothing to keep it alive. Docker sees an empty container and shuts it down.

The fix is to run your process in the foreground. Most servers have a flag for this. Nginx uses daemon off, and many tools have a --foreground or -f option. The main process must block and keep running, or the container will not stay up.

Avoid using bash or sleep tricks as a permanent fix. They keep the container alive but do not run your actual service.

Pros: Running in the foreground is the correct, clean way to keep a container alive. Cons: You must know the right flag for each service. Some legacy apps assume a background mode and need a wrapper to run correctly.

Choose The Right Restart Policy For Your Needs

Your restart policy controls how aggressively Docker brings a dead container back. Picking the wrong one can turn a single crash into an endless loop. Understanding the four options helps you avoid that.

The no policy never restarts the container. The on-failure policy restarts only when the exit code is nonzero, and you can set a max retry count. The always policy restarts no matter what, even after a clean exit. The unless-stopped policy acts like always, but it respects a manual stop and does not restart after a daemon reboot in that case.

For most production apps, unless-stopped is the safest choice. It keeps your service running but still obeys you when you stop it on purpose. The on-failure:5 option is great for tasks that may fail a few times but should give up eventually.

To set a policy, use a flag like --restart unless-stopped on docker run, or add restart: unless-stopped under your service in Compose.

Pros: A smart policy keeps healthy apps running and prevents infinite retries on broken ones. Cons: always can hide real failures and mask a crash loop. Use it with care, and always pair it with monitoring.

Set Up Log Rotation And Monitoring To Prevent Future Loops

Prevention beats firefighting. A restart loop can fill your disk with log files in minutes. The default json-file driver writes every line to disk with no limit, so a crashing container can write gigabytes fast and crash the host too.

Add log rotation in your daemon.json file:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

This caps each log file and keeps only a few rotations. Your disk stays safe even during a loop.

Beyond logs, watch the restart count. Set up an alert that fires when RestartCount rises on a container that should be stable. An increase of more than one restart in ten minutes is a strong warning sign. Monitoring memory usage against the limit also lets you catch an out of memory crash before it happens.

Pros: Log rotation protects your disk, and monitoring catches loops early before they cause damage. Cons: Setup takes a little time, and you may need a monitoring tool. The config also requires a Docker daemon restart to take effect.

A Step By Step Checklist To Diagnose Any Restart Loop

When a loop hits, follow this order every time. A clear process beats random guessing. Each step builds on the last and narrows the cause fast.

First, confirm the loop is active. Run docker ps --filter status=restarting to see which containers are cycling. Second, freeze the container with docker update --restart=no so you can inspect it calmly.

Third, read the exit code with docker inspect. This single number points you at memory, code, command, or dependency issues. Fourth, read the logs with docker logs --tail 100 to find the exact error message.

Fifth, match the cause to the fix. 137 means raise memory, 1 means check the app, 127 means fix the command, 143 means tune the health check. Sixth, apply the fix, restore your restart policy, and redeploy. Seventh, add monitoring so you catch the next loop early.

Pros: A fixed checklist makes diagnosis fast and repeatable, even for new team members. Cons: It assumes you have command line access to the host. In some locked down or managed environments, you may need to adapt these steps.

Frequently Asked Questions

Why does my container keep restarting even though the app seems fine?

Your main process is likely exiting early or running in the background. Docker needs a foreground process that keeps running. Check the logs and exit code. A clean exit with code 0 plus an always policy also causes endless restarts.

How do I see why a Docker container exited?

Run docker inspect --format '{{.State.ExitCode}} {{.State.OOMKilled}}' <container> to get the exit code. Then run docker logs --tail 100 <container> to read the error output. Together, these two commands reveal almost every cause.

What does exit code 137 mean in Docker?

Exit code 137 means the process received a SIGKILL signal. Most often, it means an out of memory kill. Check if OOMKilled is true. If it is, your container exceeded its memory limit, and you should raise the limit or fix a leak.

How do I stop a container from restarting in a loop?

Run docker update --restart=no <container_id>. This disables the restart policy on the running container, so it stays stopped after the next crash. You can then inspect it safely without it disappearing every few seconds.

Is using restart always a good idea?

It depends. The always policy restarts the container no matter what, which can hide real crashes and create loops. For most apps, unless-stopped is safer because it respects manual stops. Always pair any restart policy with proper monitoring.

Can a health check cause a restart loop?

Yes. If the health check runs before your app finishes starting, it marks the container unhealthy too soon. With an autoheal tool or orchestrator, this triggers a restart. Increase the start_period to give your app enough time to boot.

Similar Posts