Linux  ·  high  ·  Containers & Kubernetes

A container keeps restarting — exit code 137, 139 or 1

The exit code says how the process died, and each one points somewhere different.

What you see

docker ps shows the container restarting repeatedly, or Kubernetes reports CrashLoopBackOff. The application logs may show nothing at all, because it was killed rather than exiting.

What is actually wrong

137 is SIGKILL, nearly always the memory limit. 143 is SIGTERM, a normal stop. 139 is a segmentation fault. 1 is the application exiting with an error, and its own logs will say why.

Codes and articles

exit code 137exit code 139OOMKilledSIGKILLCrashLoopBackOffexit code 143

Fixes (3)

Establish whether the limit is too low or the application leaks
Root shell40 minutesmedium riskreversible

137, or the state shows OOMKilled.

  1. Confirm it was the memory limit rather than the host running out.

    Shell
    docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}} {{.HostConfig.Memory}}' mycontainerdmesg -T | grep -i 'killed process' | tail

    A container killed by its own cgroup limit and a container killed because the host ran out of memory look identical from the outside and need opposite fixes — one is a limit that is too low, the other is a host that is over-committed.

  2. Watch its usage against the limit before changing anything.

    Shell
    docker stats --no-stream
  3. If usage climbs steadily and never falls, it is a leak in the application and raising the limit only lengthens the interval between restarts.

  4. For a JVM or Node application, make sure the runtime knows about the container limit — by default many runtimes read the host's total memory and size their heap for that.

    Shell
    docker run -e JAVA_OPTS='-XX:MaxRAMPercentage=75' myimage

    This is a specific and extremely common cause: a JVM in a 512MB container sizing its heap against a 64GB host, then being killed the moment it grows into it.

  5. Set a limit that reflects measured usage plus headroom.

    Shell
    docker update --memory 1g --memory-swap 1g mycontainer
  6. In Kubernetes, set requests and limits together and keep them close for predictable scheduling.

    Shell
    kubectl describe pod mypod | grep -A5 -E 'Limits|Requests|Last State'
Confirm it workedThe container runs for a full day without restarting and usage plateaus below the limit.
Shell
docker ps --format 'table {{.Names}}\t{{.Status}}'
If you need to undo itdocker update with the previous values.
Investigate a segmentation fault in the container
Root shell40 minuteslow riskreversible

139.

  1. Check the architecture. An image built for arm64 running on x86 through emulation is a frequent cause.

    Shell
    docker image inspect myimage --format '{{.Architecture}} {{.Os}}'uname -m

    Multi-architecture registries hand out whatever matches, and a pinned digest from another machine may not. This produces an immediate segfault with no useful log at all.

  2. Check the base image's libc against the binary — a binary built against glibc will not run on an Alpine (musl) base.

  3. Run the image interactively to see the failure directly.

    Shell
    docker run --rm -it --entrypoint /bin/sh myimage
  4. Check for a seccomp or AppArmor profile blocking a system call, which can present as a crash.

    Shell
    docker run --rm --security-opt seccomp=unconfined myimage

    Running unconfined is a diagnostic, not a fix. If it resolves the crash, the answer is a profile that permits the specific call, not permanently disabling the sandbox.

  5. Rebuild the image on the target architecture, or pull the correct platform explicitly.

    Shell
    docker pull --platform linux/amd64 myimage
Confirm it workedThe container starts and stays up with the security profile back in place.
If you need to undo itRemove any --security-opt override once the specific cause is addressed.
Read what the application said before it exited
Root shell25 minuteslow riskreversible

Exit code 1 or another application-level code.

  1. Read the logs from the previous run, not the current one — the container has already restarted.

    Shell
    docker logs --tail 100 mycontainerdocker logs --tail 100 --since 10m mycontainer
  2. In Kubernetes, the previous container's logs are the ones that matter.

    Shell
    kubectl logs mypod --previous --tail=100kubectl describe pod mypod | tail -20

    Without --previous you get the logs of the container that is currently starting, which has not failed yet. This is the single most useful flag for a CrashLoopBackOff and it is easy to miss.

  3. Check the environment and configuration the container actually received — a missing variable is the usual cause.

    Shell
    docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' mycontainer
  4. Check it can reach its dependencies. A database that is not up yet makes a container exit immediately and restart forever.

    Shell
    docker run --rm --network container:mycontainer nicolaka/netshoot nc -zv db 5432
  5. Override the entrypoint to get a shell inside the failing image and test by hand.

    Shell
    docker run --rm -it --entrypoint /bin/sh myimage
Confirm it workedThe container starts cleanly and stays in the running state.
If you need to undo itDiagnostics only.

Where this stops. This write-up was written and checked by hand. It says what each step changes, how to confirm it worked and how to reverse it, and anything destructive is flagged before you reach it. If it does not match what your machine is doing, search the Support Centre for the exact code or message — and when something needs a person, get in touch.