Exit Code 143: What SIGTERM Means in Docker and Kubernetes
Updated July 27, 2026
kubectl describe pod <pod-name> and read the Events. If your app needs cleanup time, handle SIGTERM and tune terminationGracePeriodSeconds (default 30s): processes that ignore SIGTERM get escalated to SIGKILL and exit 137 instead.kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].lastState.terminated}'Causes at a glance
| Cause | How to recognize it | Fix |
|---|---|---|
| Rolling deployment | Events show Killing while a new ReplicaSet scales up | Expected behavior: make sure the app shuts down cleanly on SIGTERM |
| Scale-down (HPA or manual) | Replica count dropped; HPA events show SuccessfulRescale | Expected: verify graceful shutdown and set a PodDisruptionBudget |
| Node drain or eviction | Node was cordoned/drained; pod rescheduled to another node | Normal during upgrades and spot reclaims; add a PodDisruptionBudget |
| Failing liveness probe | Events show "Liveness probe failed" just before Killing | Fix the probe endpoint or timing so kubelet stops restarting the pod |
| docker stop / compose down | Manual or scripted stop outside Kubernetes | Expected: raise the grace period with docker stop -t if cleanup is slow |
What exit code 143 actually means
Linux reports a signal death as 128 + the signal number. SIGTERM is signal 15, so 128 + 15 = 143. SIGTERM is the catchable "please shut down" signal: the process is allowed to finish requests, flush buffers, and exit on its own terms.
That also means 143 is informative: if your app caught SIGTERM and exited cleanly, it would typically return 0. Seeing 143 usually means the default signal handler killed the process mid-work: nothing broke, but nothing was cleaned up either.
echo $((128 + 15)) # 143 = SIGTERM (graceful stop requested)
echo $((128 + 9)) # 137 = SIGKILL (force-killed)Step 1: find out who sent the SIGTERM
The signal itself carries no sender information, but Kubernetes leaves a paper trail. Correlate the termination timestamp with events: a deploy shows ScalingReplicaSet, a probe failure shows "Liveness probe failed", a drain shows the node being cordoned.
kubectl describe pod <pod-name> | grep -A 10 Events
kubectl get events --sort-by=.lastTimestamp -n <namespace>
# look for: Killing, ScalingReplicaSet, Liveness probe failed, NodeNotReadyStep 2: handle SIGTERM in your application
Register a SIGTERM handler that stops accepting new work, finishes in-flight requests, closes connections, and exits. Without one, requests in flight are dropped the moment the process dies, which is why 143s during deploys correlate with 5xx spikes.
Watch out for the PID 1 trap: with a shell-form ENTRYPOINT (ENTRYPOINT npm start), the shell is PID 1 and does not forward SIGTERM to your app, so the container ignores the signal until SIGKILL. Use the exec form (ENTRYPOINT ["node", "server.js"]), exec inside wrapper scripts, or an init like tini (docker run --init).
// Node.js
process.on('SIGTERM', () => {
server.close(() => process.exit(0));
});
# Python
import signal, sys
signal.signal(signal.SIGTERM, lambda *_: sys.exit(0))Step 3: give shutdown enough time (grace period and preStop)
Kubernetes runs the preStop hook first, then sends SIGTERM, then waits out terminationGracePeriodSeconds (default 30s, counted from termination start, including preStop) before SIGKILL. A short preStop sleep gives load balancers time to remove the pod from endpoints before the app stops accepting traffic.
spec:
terminationGracePeriodSeconds: 60
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["sleep", "10"] # let endpoints/LBs drain firstExit code 143 vs 137
They are the two halves of the same shutdown protocol: 143 means the process died on SIGTERM (the polite request), 137 means it was force-killed with SIGKILL: either because it ignored SIGTERM past the grace period, or because the OOM killer fired. If your deploys produce 137s instead of 143s, your shutdown handler is too slow or not receiving the signal at all.
Every 143 is the fingerprint of an intentional action: something initiated that shutdown. When AI agents run deploys and scale services, "who terminated these pods" needs a better answer than a service-account name in an audit log. Nexus records each agent-initiated rollout and scaling action with the full context of why the agent did it, so a wave of SIGTERMs traces back to the exact decision that caused it.
Explore Swfte NexusCommon questions
- Is exit code 143 an error?
- Usually not. It means the container was asked to stop with SIGTERM and did, which is exactly what happens in every rolling deploy, scale-down, and node drain. It only indicates a problem when it appears outside those lifecycle events, or when your app needed to clean up and did not.
- Why do my pods exit with code 143 during every deploy?
- Because a rolling update terminates old pods with SIGTERM as new ones become ready. That is by design. The thing to verify is that your app handles SIGTERM gracefully so in-flight requests finish instead of being dropped.
- Why does my container ignore SIGTERM and get SIGKILLed instead?
- Most often because a shell is PID 1 and swallows the signal: a shell-form ENTRYPOINT or a wrapper script that does not use exec. Switch to the exec form of ENTRYPOINT, prefix the final command in scripts with exec, or run with an init process like tini.
- How long does Kubernetes wait after sending SIGTERM?
- terminationGracePeriodSeconds, which defaults to 30 seconds and includes any preStop hook time. If the process is still alive when it expires, the kubelet sends SIGKILL and the container exits 137.
- What is the difference between exit code 143 and exit code 137?
- 143 is SIGTERM (128+15): a graceful stop the process could react to. 137 is SIGKILL (128+9): an unblockable force kill, caused by the OOM killer or by a grace period expiring. 143 is normally fine; 137 always deserves a look.