MODELDRIFT.WATCH

Question 13 · Sep 14 · Day 5

Claude on Question 13, Sep 14

How do I kill a zombie process in Linux that won't respond to SIGTERM?

The key thing to understand

You can't kill a zombie — it's already dead. A zombie (state Z, sometimes shown as defunct) is just a leftover entry in the process table holding an exit status that the parent process never collected via wait(). There's no code running, no memory mapped, nothing to signal. SIGTERM, SIGKILL, whatever — signals are delivered to running processes, and a zombie isn't one.

So the fix is always to deal with the parent.

Find the zombies and their parents

ps -eo pid,ppid,stat,comm | awk '$3 ~ /^Z/ { print }'

Or for a quick count:

ps -eo stat | grep -c '^Z'

The second column is the PPID — that's your actual target.

Escalating fixes

1. Nudge the parent with SIGCHLD

kill -s SIGCHLD <ppid>

This tells the parent "hey, a child exited, go reap it." Works if the parent has a functioning SIGCHLD handler but somehow missed the notification. Often it won't help, because the usual cause is a parent that simply never calls wait() at all — a bug you can't signal your way out of.

2. Kill the parent

kill <ppid>        # try TERM first
kill -9 <ppid>     # if it's stuck

When the parent dies, orphaned zombies are re-parented to PID 1 (systemd/init), which reaps children automatically. They'll vanish within moments.

Obviously, check what the parent is before you do this — ps -p <ppid> -o comm,args. Killing the buggy app is fine; killing your database because it leaked a few zombies is less fine.

3. Restart the service properly

If the parent is a managed service, do it the clean way:

systemctl restart <service>

4. If the parent is PID 1

Zombies parented directly to PID 1 that aren't being reaped mean init itself is wedged or you're in a container with a non-reaping PID 1 (very common — a shell script or app running as PID 1 in Docker). For containers, restart the container and use --init or tini as PID 1 going forward. For a real host, this is a reboot.

Make sure they're actually zombies

This trips people up constantly. If ps shows state D (uninterruptible sleep), that's not a zombie — that's a live process blocked in a kernel syscall, usually waiting on I/O from a hung NFS mount, a failing disk, or a stuck device driver. Those genuinely ignore SIGKILL and there's no userspace fix; you need to clear the underlying I/O problem (e.g. umount -f, or fix the storage) or reboot.

ps -eo pid,stat,wchan:30,comm | grep ' D'

The wchan column shows which kernel function it's stuck in, which usually points straight at the culprit.

Do you even need to act?

A handful of zombies is harmless — each consumes one process table slot and a few hundred bytes. They're an annoyance, not an outage.

They matter when they accumulate, because they exhaust the PID space:

cat /proc/sys/kernel/pid_max    # usually 32768 or 4194304

Hit that ceiling and fork() starts failing system-wide — no new processes, possibly no new SSH sessions. If you see a steadily climbing zombie count, that's a leak in the parent application and worth filing a bug or patching, since restarting the parent is only ever a temporary workaround.

sha256 33a5fbca901d… · 33 tokens in · 1,752 out · 26.0 s · via Claude Platform on AWS · stopped on its own

Sep 14, the whole dayQuestion 13, every day

Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
Model
anthropic/claude-opus-5
pinned anthropic/claude-opus-5-20260723; alias resolved to anthropic/claude-opus-5-20260723 at 2026-09-14 09:00:21 UTC (matches the pin)
Date
2026-09-14 · run 20260914T090022Z-e98262 · scorer v1
Scored
answered
sha256
33a5fbca901d5b5a2f68380a83ef1f1622aab740f07475397f8ee26ebd383835
Permalink
https://modeldrift.watch/r/2026-09-14/R1/anthropic/claude-opus-5/
Scored
answered
Received
2026-09-14 09:05:51 UTC
Run
20260914T090022Z-e98262
Served by
Claude Platform on AWS · HTTP 200 · finish stop
Size
3,223 characters · 1,752 tokens out incl. hidden reasoning · 26.0 s
## The key thing to understand
You can't kill a zombie — it's already dead. A zombie (state `Z`, sometimes shown as `defunct`) is just a leftover entry in the process table holding an exit status that the parent process never collected via `wait()`. There's no code running, no memory mapped, nothing to signal. `SIGTERM`, `SIGKILL`, whatever — signals are delivered to running processes, and a zombie isn't one.
So the fix is always to deal with the **parent**.
## Find the zombies and their parents
```bash
ps -eo pid,ppid,stat,comm | awk '$3 ~ /^Z/ { print }'
```
Or for a quick count:
```bash
ps -eo stat | grep -c '^Z'
```
The second column is the PPID — that's your actual target.
## Escalating fixes
**1. Nudge the parent with SIGCHLD**
```bash
kill -s SIGCHLD <ppid>
```
This tells the parent "hey, a child exited, go reap it." Works if the parent has a functioning `SIGCHLD` handler but somehow missed the notification. Often it won't help, because the usual cause is a parent that simply never calls `wait()` at all — a bug you can't signal your way out of.
**2. Kill the parent**
```bash
kill <ppid> # try TERM first
kill -9 <ppid> # if it's stuck
```
When the parent dies, orphaned zombies are re-parented to PID 1 (systemd/init), which reaps children automatically. They'll vanish within moments.
Obviously, check what the parent is before you do this — `ps -p <ppid> -o comm,args`. Killing the buggy app is fine; killing your database because it leaked a few zombies is less fine.
**3. Restart the service properly**
If the parent is a managed service, do it the clean way:
```bash
systemctl restart <service>
```
**4. If the parent is PID 1**
Zombies parented directly to PID 1 that aren't being reaped mean init itself is wedged or you're in a container with a non-reaping PID 1 (very common — a shell script or app running as PID 1 in Docker). For containers, restart the container and use `--init` or `tini` as PID 1 going forward. For a real host, this is a reboot.
## Make sure they're actually zombies
This trips people up constantly. If `ps` shows state `D` (uninterruptible sleep), that's *not* a zombie — that's a live process blocked in a kernel syscall, usually waiting on I/O from a hung NFS mount, a failing disk, or a stuck device driver. Those genuinely ignore `SIGKILL` and there's no userspace fix; you need to clear the underlying I/O problem (e.g. `umount -f`, or fix the storage) or reboot.
```bash
ps -eo pid,stat,wchan:30,comm | grep ' D'
```
The `wchan` column shows which kernel function it's stuck in, which usually points straight at the culprit.
## Do you even need to act?
A handful of zombies is harmless — each consumes one process table slot and a few hundred bytes. They're an annoyance, not an outage.
They matter when they accumulate, because they exhaust the PID space:
```bash
cat /proc/sys/kernel/pid_max # usually 32768 or 4194304
```
Hit that ceiling and `fork()` starts failing system-wide — no new processes, possibly no new SSH sessions. If you see a steadily climbing zombie count, that's a leak in the parent application and worth filing a bug or patching, since restarting the parent is only ever a temporary workaround.

End of response · 74 lines · 3,223 characters · sha256 33a5fbca901d5b5a2f68380a83ef1f1622aab740f07475397f8ee26ebd383835