Skip to content
Latchkey

Docker ENTRYPOINT/CMD Shell Form - Signals Ignored, Container Won’t Stop

A shell-form ENTRYPOINT cmd / CMD cmd runs your process as a child of /bin/sh -c, which becomes PID 1 and does not forward signals. The container ignores SIGTERM, so docker stop waits the full grace period then SIGKILLs it.

What this error means

docker stop (or compose down) takes ~10 seconds per container before exiting, and the app never runs its graceful-shutdown logic. In CI this slows teardown and can leave work unflushed.

Dockerfile / docker stop
# Dockerfile (shell form - sh is PID 1, signals not forwarded):
ENTRYPOINT node server.js
# docker stop hangs for the 10s grace period, then:
# container exited with code 137 (SIGKILL after timeout)

Common causes

Shell form wraps the process in /bin/sh

Shell form (ENTRYPOINT cmd) is implicitly /bin/sh -c "cmd". sh becomes PID 1, and by default it does not propagate SIGTERM to your process, so graceful shutdown never fires.

No init to reap/forward signals

Without exec form or an init, the app does not receive stop signals and docker stop falls back to killing it after the timeout.

How to fix it

Use exec form so your process is PID 1

JSON-array (exec) form runs the binary directly, so it receives signals.

Dockerfile
ENTRYPOINT ["node", "server.js"]
# or, if you need a shell, exec into the process:
ENTRYPOINT ["/bin/sh", "-c", "exec node server.js"]

Add a tiny init for signal handling

When the entrypoint must be a shell script, run it under an init that forwards signals and reaps zombies.

Terminal / docker-compose.yml
# docker run --init ...  (uses tini)
# or in compose:
services:
  api:
    init: true

How to prevent it

  • Prefer JSON-array (exec) form for ENTRYPOINT and CMD.
  • Use exec in entrypoint scripts so the final process replaces the shell.
  • Enable --init for images that legitimately need a shell wrapper.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →