macOS: long-running session leaks /dev/ptmx masters, exhausts kern.tty.ptmx_max (forkpty ENXIO system-wide)
Summary
A long-running Claude Code CLI session on macOS accumulates a large number of /dev/ptmx master pseudo-terminals held open by its process, without releasing them. Because macOS caps the total system-wide pty count (kern.tty.ptmx_max, default 511), a single long-lived session can consume a large fraction of the pool, and once the aggregate hits the cap every forkpty() on the machine fails with ENXIO ("Device not configured") — new Terminal/kitty windows and any subprocess that needs a pty stop opening, system-wide.
Observed (verified)
On a session that had been running a while:
$ lsof /dev/ptmx | wc -l
101
# ranked holders:
101 Claude <pid> # one Claude Code process holding 101 ptmx masters
$ sysctl kern.tty.ptmx_max
kern.tty.ptmx_max: 511
One Claude Code process held 101 open /dev/ptmx masters. The pool sat at 117/511; under more concurrent sessions (or a longer-lived one) this reaches 511 and forkpty: Device not configured follows for everything on the system.
Likely cause (inference, not confirmed from source)
It looks like pty masters allocated for shell / Bash-tool / subprocess execution are not being closed/reaped promptly after each command completes, so the count grows monotonically over a session's lifetime rather than staying proportional to concurrent in-flight commands. ~100 masters for one session is far above what concurrent execution should need.
Repro (expected)
- macOS (default
kern.tty.ptmx_max=511). - Run a Claude Code session that executes many Bash/tool commands over an extended period (and/or several concurrent sessions).
- Watch
lsof /dev/ptmx | awk '{print $1,$2}' | sort | uniq -c | sort -rn— the Claude process's master count climbs and does not fall back as commands finish. - Eventually
forkpty()returnsENXIOand new shells/terminals fail until sessions are quit / logout / reboot.
Impact
System-wide: once the pool is exhausted, Terminal, kitty, and any pty-needing process fail to start — not just Claude Code. Recovery today is to quit idle Claude sessions, log out, or reboot.
Ask
- Does Claude Code close pty master fds after each subprocess/Bash-tool invocation completes? An accumulation to ~100 per session suggests masters are retained for the session lifetime.
- If retention is intended, consider reaping on command completion, or bounding the per-session master count.
Environment
- OS: macOS (Darwin 25.5.0)
- Claude Code CLI (Opus 4.x)
kern.tty.ptmx_maxdefault 511; macOS hard max is 999 (PTMX_MAX_HARD, XNUbsd/kern/tty_ptmx.c).
Workaround (bridge only, not a fix)
Raise the cap: sudo sysctl -w kern.tty.ptmx_max=999 (immediate; resets on reboot; 999 is the kernel hard max). This only buys headroom — it does not stop the accumulation.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗