Claude Desktop leaks pseudo-terminals (ptmx) until the macOS pty pool is exhausted, breaking Terminal.app
Summary
The Claude Desktop app leaks pseudo-terminal master handles (/dev/ptmx) over time and never releases them. After ~1.5 days of uptime the app held 511 open ptmx handles — the entire system pool (kern.tty.ptmx_max = 511). Once exhausted, no other process can allocate a pty: launching Terminal.app fails with:
forkpty: Device not configured
Could not create a new process and open a pseudo-tty.
Impact
System-wide pty starvation. Terminal, iTerm, ssh, and any tool needing a pty stop working until the Claude Desktop app is quit. Looks like an OS fault, not an app bug — easy to misdiagnose as needing a reboot.
Environment
- macOS 26.5.1 (build 25F80), Apple Silicon
- Claude Desktop 1.11847.5
- Claude Code (local agent mode) 2.1.170
kern.tty.ptmx_max= 511 (default)
Evidence
$ lsof -n /dev/ptmx | awk 'NR>1{print $1}' | sort | uniq -c | sort -rn
511 Claude
$ lsof -n /dev/ptmx | wc -l
512 # 511 handles + header
All 511 handles owned by a single PID = /Applications/Claude.app/Contents/MacOS/Claude (parent = launchd), elapsed time ~1 day 12 hours. No live shell processes are attached to a tty (ps tty column empty), so these are leaked master fds held open after the child processes exited — not active terminals.
Leak rate ≈ 340 ptys/day, consistent with bash/tool-execution in local agent mode spawning a pty per call and not closing the master on completion.
Reproduction
- Run Claude Desktop with local agent (Claude Code) mode, using the Bash/tool-execution features over an extended session (~1 day).
- Periodically check
lsof -n /dev/ptmx | wc -l— count climbs monotonically and never drops. - When it reaches
kern.tty.ptmx_max(511), Terminal.app fails withforkpty: Device not configured.
Workaround
Quit and relaunch Claude Desktop — releases all handles immediately, no reboot needed.
Likely fix
Ensure the pty master fd is closed when a spawned tool/bash process exits (the slave side closing on child exit doesn't free the master if the app still holds the master open).
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗