github →

New request

#2577: [bug] api/terminal.py: Node child processes become zombies when Popen handle is not reaped (same class as #1912)

We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.

Issue
bugsprint-candidateperformance

Sonnet analysis.

Description

Observed two [node] <defunct> zombie processes (PIDs 2860182, 2909786) as children of the hermes-webui server process (PID 2872805), both dating from May 13. The Python parent is still alive but has never reaped these children.

This is the same class of bug identified in #1912 for api/providers.py, but in api/terminal.py, which uses a persistent subprocess.Popen handle (line 42) to manage long-lived processes.

Root cause

api/terminal.py spawns Node child processes via subprocess.Popen but does not guarantee .wait() is called when the child exits — particularly when the terminal session is closed or an error path is taken. The Python parent remains alive, so the kernel cannot auto-reap the children, leaving them as zombies.

Missing mitigations (per #1912)

  • No preexec_fn=_set_pdeathsig — Node children survive parent SIGKILL
  • No .wait() / communicate() call on the cleanup path
  • No stdin=DEVNULL

Suggested fix

Apply the same prctl(PR_SET_PDEATHSIG) pattern already recommended in #1912, plus ensure the cleanup path always calls .wait():

import ctypes, signal

def _set_pdeathsig():
    PR_SET_PDEATHSIG = 1
    ctypes.CDLL("libc.so.6").prctl(PR_SET_PDEATHSIG, signal.SIGTERM)

proc = subprocess.Popen(
    [...],
    preexec_fn=_set_pdeathsig,
    stdin=subprocess.DEVNULL,
)

References

  • #1912 — same pattern in api/providers.py
  • #1873 — original subprocess isolation PR

Assessmentadvisory
bug easy95% confidence

This is a localized process-reaping bug in api/terminal.py that can be fixed by applying the established subprocess lifecycle pattern.

Likely files
  • api/terminal.py
  • tests/test_terminal.py
Create the request

This opens a fresh agent run and a draft PR for issue #2577.

Cancel