Skip to content

pty-daemon leaks pty master fds for exited agents → exhausts kern.tty.ptmx_max, blocks all new agent spawns (and other apps) #5305

Closed

Description

@sburl

Summary

The pty-daemon does not close the pty master fd when an agent/terminal session exits. Over a long uptime with high agent churn, leaked ptys accumulate without bound until the host hits macOS's kern.tty.ptmx_max (511 on this machine). At that point no new agent can spawn, and even unrelated apps can no longer allocate a terminal.

Environment

  • Superset v1.12.3 (running process) / 1.12.5 (installed), com.superset.desktop
  • macOS (Apple Silicon)

Symptoms

  • New agent launches fail with:
    Error: open <uuid>: spawn failed (shell=/bin/zsh cwd=.../worktrees/.../bot/<branch> errno=ok): posix_spawnp failed.
    
  • Unrelated terminal apps (e.g. Ghostty) report: "Your system cannot allocate any more pty devices."

Evidence (captured on a live, wedged daemon)

  • lsof -p <pty-daemon-pid> → 1425 open fds, 473 of them /dev/tty* (pty) devices.
  • Only ~17 ptys map to a live process (ps -Ao tty) → ~456 are ghosts of agents that already exited.
  • pty-daemon uptime ~11 days; hundreds of CLI agents launched and torn down across git worktrees in that window.
  • ls /dev/ttys* | wc -l ≈ 490 vs sysctl -n kern.tty.ptmx_max = 511.

Killing the orphaned agent shells only frees a handful; the bulk of the leak is master-side fds held open by the daemon itself, invisible to ps tty.

Root cause

The pty master fd is not released on agent process exit / session teardown. The leak is monotonic and proportional to lifetime agent count, not concurrent sessions — so it always grows until a restart, and high-throughput orchestration (the product's core use case: dozens of agents in parallel) hits the ceiling fast.

Workaround

Restart Superset — releases all daemon fds at once; pty count drops back to the dozen or so actually in use.

Suggested fix

Close/reap the pty master when the child agent process exits, and on failed/aborted spawns (which also appear to leak a half-initialized pty).

Activity

  1. added a commit that references this issue on Jun 18, 2026
  2. Kitenite commented on Jul 12, 2026

    @Kitenite
    Member

    Fixed by #5438: the terminal reaper now runs in the desktop host-service entry, so pty masters for exited sessions are closed instead of accumulating toward kern.tty.ptmx_max. #5067 also raised the daemon fd limit and surfaces the real spawn errno. Reopen if exhaustion recurs on 1.13+.

  3. AlexGodard commented on Jul 19, 2026

    @AlexGodard

    Requesting reopen — the exhaustion has recurred on a 1.13+ build, per the closing comment's condition.

    Environment

    • Superset Canary 1.15.1-canary.20260719002739 (/Applications/Superset Canary.app), macOS 26.5.2 (Apple Silicon)
    • The leaking process is the spawned pty daemon: … app.asar/dist/main/pty-daemon.js --socket=/tmp/superset-ptyd-….sock, uptime ~5.5 days
    • Heavy agent churn over that window (fleet orchestration creating/tearing down many CLI-agent workspaces)

    Evidence (live right now)

    Possible gap in the fix

    #5438 started the terminal reaper "in the desktop host-service entry" — but the fd holder here is the standalone pty-daemon.js process, not the desktop host-service. If the reaper only closes masters tracked in the host-service process, masters owned by the detached pty daemon would still accumulate exactly as observed. (The daemon being spawned detached is also the subject of #5423, so this split-process arrangement is recent.)

    Happy to run any diagnostics against the live wedged daemon before I restart it.

  4. Kitenite commented on Jul 19, 2026

    @Kitenite
    Member

    Thanks @AlexGodard re opening

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions