<!-- canonical: https://docs.axelabs.ai/ops/reports/claudeapp-fd-leak-2026-05 -->
<!-- source: content/ops/reports/claudeapp-fd-leak-2026-05.mdx -->

---
title: Claude Desktop PTY/fd leak — bug report draft (2026-05)
description: macOS Claude.app 의 /dev/ptmx fd 누적 leak 으로 1-2 주 가동 후 forkpty ENXIO 차단. Anthropic support 또는 claude-code GitHub issue 제출용 draft.
---

# Claude Desktop PTY/fd leak — bug report draft (2026-05)

> **상태**: Draft. 운영자 검토 후 `support@anthropic.com` 또는 [claude-code GitHub issues](https://github.com/anthropics/claude-code/issues) 에 그대로 전송 가능한 self-contained 리포트.
>
> **Backlog**: [B-claudeapp-fd-leak-anthropic-report](/ops/backlog) · **Tracking**: [B-claude-desktop-pty-leak-track](/ops/backlog) · **Mitigation**: [B-axe-pty-max-launchd](/ops/backlog)
>
> **관련 분석**: [Claude.app /dev/ptmx fd leak (known-gaps)](/ops/known-gaps)

---

## 1. Summary

Claude Desktop on macOS leaks file descriptors to `/dev/ptmx`, accumulating fd usage over weeks of normal operation until the system-wide `kern.tty.ptmx_max` limit is reached. After that, new terminal/PTY spawns fail with `forkpty: Device not configured` (ENXIO), affecting all macOS users on the host (not just Claude.app itself). The only known fix is to quit and restart Claude Desktop, which reclaims all leaked fds.

## 2. Environment

- **OS**: macOS (Darwin 25.3.0 at time of reproduction)
- **App**: Claude Desktop — `/Applications/Claude.app/Contents/MacOS/Claude`
- **Hardware**: Apple Silicon mac mini
- **Uptime at failure**: 43+ days continuous operation (observed 2026-05-26)
- **PTY limit**: `kern.tty.ptmx_max` = 511 (macOS default; sysctl raise to 2047 is rejected by kernel)

## 3. Symptom

### 3.1 Failure mode

- New terminal spawns (Terminal.app, iTerm2, Claude Code subprocess `forkpty()`) are denied with ENXIO.
- Error string: `forkpty: Device not configured`
- **Scope**: system-wide — not limited to Claude.app. All users on the host lose the ability to allocate new PTYs until the leak is cleared.

### 3.2 Reproduction

1. Use Claude Desktop normally on a macOS host (open many chats, close them, leave the app running).
2. After 1–2 weeks of continuous uptime, monitor PTY fd consumption:
   ```bash
   sudo lsof /dev/ptmx | grep -i Claude | wc -l
   ```
   Count grows steadily over time.
3. When the total `lsof /dev/ptmx` count reaches `kern.tty.ptmx_max` (default 511), `forkpty: Device not configured` starts to fire on every new PTY allocation attempt.

### 3.3 Diagnosis commands

```bash
# Per-process PTY fd occupancy (sorted)
sudo lsof /dev/ptmx | awk '{print $1}' | sort | uniq -c | sort -rn

# Kernel PTY ceiling
sysctl kern.tty.ptmx_max

# Detailed fd list for Claude.app PID
ps aux | grep -i Claude
sudo lsof -p <claude-pid> | grep /dev/ptmx | wc -l
```

### 3.4 Observed data (2026-05-26, operator host)

- Claude.app PID held fds 43, 44, 46, 88, 89, 92, 94, 98, 99, 102+ against `/dev/ptmx`.
- Reaping userspace zsh zombies (82 accumulated, all Claude Code subprocesses) did **not** release the ptmx fds — confirming the leak is in Claude.app proper, not in spawned shells.

## 4. Workarounds (current)

| Action | Effect | Notes |
|---|---|---|
| Quit + relaunch Claude Desktop | Immediate: all leaked fds reclaimed | Only known reliable fix |
| `sudo sysctl -w kern.tty.ptmx_max=2047` | Ineffective | Kernel rejects values above 511 on current macOS |
| launchd plist for boot-time sysctl ([B-axe-pty-max-launchd](/ops/backlog)) | Pending validation | Likely also rejected by kernel; tracked as long-term mitigation |

## 5. Suspected root cause

- Claude.app spawns PTY-backed subprocesses (IPC helpers, terminal-like surfaces) without releasing the master fd when the subprocess exits or the chat is closed.
- Reaping orphaned userspace `zsh` zombies (Claude Code subprocesses) does not free the `/dev/ptmx` fds — strongly suggests the leak is in the Claude.app process holding the master end open after the slave has gone away.
- Pattern is consistent with missing `close()` on the master fd in a subprocess lifecycle path.

## 6. Impact

- **Affected users**: macOS users running Claude Desktop with long uptime (1–2 weeks+) and any non-trivial chat volume.
- **Blast radius**: system-wide PTY denial — all terminal applications on the host are blocked from spawning new sessions, not just Claude.app.
- **Detectability**: silent until the limit is hit; the failure surfaces in unrelated apps (Terminal.app, iTerm2) and is hard to attribute to Claude.app without running `lsof /dev/ptmx`.

## 7. Requested fix

1. Audit Claude.app's PTY subprocess lifecycle — ensure master fds are `close()`d when the slave end exits or the owning chat/IPC channel is torn down.
2. Guarantee close-on-exit semantics for all spawned PTYs.
3. Add a self-check in the production build: if Claude.app's own `/dev/ptmx` fd count exceeds a threshold (e.g. 100), emit a telemetry event so this regression is caught automatically in future releases.

## 8. Attachments / references

- Operator known-gaps entry: [Claude.app /dev/ptmx fd leak](/ops/known-gaps)
- Related operator backlog items:
  - `B-claude-desktop-pty-leak-track` — tracking the recurrence
  - `B-axe-pty-max-launchd` — host-side mitigation attempt
  - `B-claudeapp-fd-leak-anthropic-report` — this report

## 9. Submission channels

- **Email**: `support@anthropic.com`
- **GitHub**: https://github.com/anthropics/claude-code/issues — cross-post recommended since the symptom also surfaces from Claude Code's subprocess `forkpty()` paths.

## 10. Status

| Field | Value |
|---|---|
| Report state | Draft |
| Submission date | TBD (운영자 결정) |
| Anthropic acknowledgement | TBD |
| Anthropic fix release | TBD |

운영자가 검토 후 위 채널 중 하나로 제출. 회신 수령 시 본 페이지 §10 표를 갱신하고 [/ops/known-gaps](/ops/known-gaps) 의 해당 항목에 진행 상황 한 줄 추가.
