[BUG] Opencode process survives terminal close — missing SIGHUP handler causes orphaned process accumulation #8871

Open
opened 2026-02-16 18:11:04 -05:00 by yindo · 1 comment
Owner

Originally created by @blackas on GitHub (Feb 8, 2026).

Originally assigned to: @rekram1-node on GitHub.

Description

When a terminal session (tab/window) is closed, the opencode process and its child LSP servers are not terminated. They remain running as orphaned processes (TTY = ??), accumulating over time and consuming significant memory.

This indicates opencode does not handle the SIGHUP signal, which the OS sends to foreground processes when their controlling terminal is closed.

Environment

  • OS: macOS 26.2 (Apple Silicon, arm64)
  • OpenCode: v1.1.53
  • Terminal: iTerm2 / Terminal.app (reproducible in both)

Steps to Reproduce

  1. Open a terminal tab and run opencode in a project directory
  2. Let it fully initialize (LSP servers spawn: pyright, bash-language-server, etc.)
  3. Close the terminal tab/window (not Ctrl+C, just close the tab or quit the terminal app)
  4. Open a new terminal and run: ps aux | grep opencode

Observed Behavior

The closed session's opencode process and all its child LSP servers remain alive as orphaned processes:

$ ps -o pid,ppid,tty,stat,etime,command | grep opencode | grep -v grep
87902 70932 ??   S    06-18:21:02 opencode          # 6+ days, no TTY
36784 22543 ??   S    02-15:52:45 opencode          # 2+ days, no TTY

Key observations:

  • TTY = ?? — controlling terminal is gone
  • STAT = S — sleeping, not zombie (still holding resources)
  • Parent PIDs point to orphaned zsh shells (re-parented to PID 1)
  • Each main process retains its child LSP servers (pyright, bash-language-server, yaml-language-server)

In my case, 10 main opencode processes + 8 child LSP servers = 18 total processes consuming ~3.2 GB RAM, most of which were from old, disconnected sessions.

Expected Behavior

When the controlling terminal is closed (SIGHUP sent):

  1. opencode should catch SIGHUP and perform graceful shutdown
  2. All child LSP server processes should be terminated
  3. No orphaned processes should remain

Root Cause Analysis

opencode does not appear to register a SIGHUP handler. The standard process lifecycle for an interactive CLI tool should handle:

Signal Expected Action
SIGHUP Graceful shutdown (terminal closed)
SIGTERM Graceful shutdown (kill request)
SIGINT Immediate exit (Ctrl+C)

Without SIGHUP handling, every terminal close event leaks one opencode process + N LSP child processes.

Impact

  • Memory leak: ~150-800 MB per orphaned session, accumulating indefinitely
  • Process table pollution: 2-5 processes per orphaned session
  • Potentially related to: #12687 (memory leak leading to kernel panic) — orphaned process accumulation could be a contributing factor
  • Similar pattern to: #12596 (LSP process leak) — both involve child processes not being cleaned up

Workaround

Manually kill orphaned processes:

# Find orphaned opencode processes (no TTY)
ps -o pid,tty,etime,command | grep opencode | grep '??'

# Kill them
kill <pid1> <pid2> ...
Originally created by @blackas on GitHub (Feb 8, 2026). Originally assigned to: @rekram1-node on GitHub. ### Description When a terminal session (tab/window) is closed, the `opencode` process and its child LSP servers are not terminated. They remain running as orphaned processes (`TTY = ??`), accumulating over time and consuming significant memory. This indicates `opencode` does not handle the `SIGHUP` signal, which the OS sends to foreground processes when their controlling terminal is closed. ### Environment - **OS**: macOS 26.2 (Apple Silicon, arm64) - **OpenCode**: v1.1.53 - **Terminal**: iTerm2 / Terminal.app (reproducible in both) ### Steps to Reproduce 1. Open a terminal tab and run `opencode` in a project directory 2. Let it fully initialize (LSP servers spawn: pyright, bash-language-server, etc.) 3. **Close the terminal tab/window** (not `Ctrl+C`, just close the tab or quit the terminal app) 4. Open a new terminal and run: `ps aux | grep opencode` ### Observed Behavior The closed session's `opencode` process and all its child LSP servers remain alive as orphaned processes: ``` $ ps -o pid,ppid,tty,stat,etime,command | grep opencode | grep -v grep 87902 70932 ?? S 06-18:21:02 opencode # 6+ days, no TTY 36784 22543 ?? S 02-15:52:45 opencode # 2+ days, no TTY ``` Key observations: - `TTY = ??` — controlling terminal is gone - `STAT = S` — sleeping, not zombie (still holding resources) - Parent PIDs point to orphaned `zsh` shells (re-parented to PID 1) - Each main process retains its child LSP servers (pyright, bash-language-server, yaml-language-server) In my case, **10 main opencode processes + 8 child LSP servers = 18 total processes consuming ~3.2 GB RAM**, most of which were from old, disconnected sessions. ### Expected Behavior When the controlling terminal is closed (SIGHUP sent): 1. `opencode` should catch `SIGHUP` and perform graceful shutdown 2. All child LSP server processes should be terminated 3. No orphaned processes should remain ### Root Cause Analysis `opencode` does not appear to register a `SIGHUP` handler. The standard process lifecycle for an interactive CLI tool should handle: | Signal | Expected Action | |--------|----------------| | `SIGHUP` | Graceful shutdown (terminal closed) | | `SIGTERM` | Graceful shutdown (kill request) | | `SIGINT` | Immediate exit (Ctrl+C) | Without `SIGHUP` handling, every terminal close event leaks one `opencode` process + N LSP child processes. ### Impact - **Memory leak**: ~150-800 MB per orphaned session, accumulating indefinitely - **Process table pollution**: 2-5 processes per orphaned session - **Potentially related to**: #12687 (memory leak leading to kernel panic) — orphaned process accumulation could be a contributing factor - **Similar pattern to**: #12596 (LSP process leak) — both involve child processes not being cleaned up ### Workaround Manually kill orphaned processes: ```bash # Find orphaned opencode processes (no TTY) ps -o pid,tty,etime,command | grep opencode | grep '??' # Kill them kill <pid1> <pid2> ... ```
yindo added the perf label 2026-02-16 18:11:04 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Feb 8, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #12687: [BUG/PERF] Severe Memory Leak and Disk Swell leading to System Kernel Panic (macOS) — directly mentioned as potentially related
  • #12596: ElixirLS: LSP client spawns new process per request, causing timeout and process leak — similar pattern of orphaned processes

Related issues that could be caused or exacerbated by orphaned process accumulation:

  • #12513: Critical CPU usage and memory leak
  • #12499: Memory consumption reaching 53% on high-end systems after hours of usage

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Feb 8, 2026): This issue might be a duplicate of existing issues. Please check: - #12687: [BUG/PERF] Severe Memory Leak and Disk Swell leading to System Kernel Panic (macOS) — directly mentioned as potentially related - #12596: ElixirLS: LSP client spawns new process per request, causing timeout and process leak — similar pattern of orphaned processes Related issues that could be caused or exacerbated by orphaned process accumulation: - #12513: Critical CPU usage and memory leak - #12499: Memory consumption reaching 53% on high-end systems after hours of usage Feel free to ignore if none of these address your specific case.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8871