Agentic AIs1 have a tendency to leak ptys2 on macOS every time they run a command, leading to pervasive errors3. You can try to raise the ceiling but not by much4, and it's tricky to persist it5.
This tool identifies and closes those leaks where possible6. Running the script raw will just identify leaks, running with --close will close them.
Code written mostly by Claude. I can't guarantee there aren't mistakes but in my own testing it seems fine and safe.
Footnotes
-
Gemini CLI and Claude Code (and potentially other node-based CLIs or agents, though they haven't been tested). ↩
-
This is a known problem caused by upstream PTY master file descriptor (
/dev/ptmx) leaks on macOS. For details and discussion on why they persist, see:- Upstream Node-PTY Issues & Fixes:
- microsoft/node-pty#710 — macOS
/dev/ptmxleak issue - microsoft/node-pty#657 — PTY leak leading to openpty failure
- microsoft/node-pty#882 — Upstream macOS fix PR: "fix: /dev/ptmx leak on macOS"
- microsoft/node-pty#931 — Fix: close kqueue fd in SetupExitCallback on macOS
- microsoft/node-pty#710 — macOS
- Gemini CLI Issues & Fixes:
- google/gemini-cli#20804 — PTY file descriptor leak issue
- google/gemini-cli#27147 — PR: Upgrade pty dependencies to pull upstream fix
- google/gemini-cli#27154 — PR: Prevent PTY memory leak by synchronously deleting active entries
- Upstream Node-PTY Issues & Fixes:
-
Pervasive errors you might see when system-wide PTY limits are exhausted:
posix_spawn failed: Resource temporarily unavailable/EAGAINforkpty: Device not configured/ENXIO(when opening terminal panes, tabs, or spawning shells)posix_openpt failed: Device not configured(in VS Code/Cursor terminal views)Could not create a new process and open a pseudo-tty.unable to allocate pty: Device not configured(when executing commands likesudo)
-
Default on macOS is 511 and the max that macOS will accept is 999:
/usr/sbin/sysctl -w kern.tty.ptmx_max=999. If your system is already out and everything is failing you can tryosascript -e 'do shell script "/usr/sbin/sysctl -w kern.tty.ptmx_max=999" with administrator privileges'instead, see microsoft/node-pty#710. ↩ -
Modern macOS (Big Sur and later) ignores
/etc/sysctl.conf. If desperate, you could fake it with a launchdaemon that runs the above command at boot. ↩ -
Does not work on
.appbundles (such as VS Code or full Electron apps) because the macOS Hardened Runtime blockslldb attacheven withsudo. However, this is not a problem for CLI-based tools likeclaudeorgemini, which run as raw node processes and can be attached to successfully. ↩