[macOS] agent-exec opens 100k+ vnode FDs while scanning nested worktrees, causing system-wide ENFILE and kernel panic

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Opening a repository that contains a very large nested worktree tree under .claude/worktrees/ causes Cursor’s built-in agent-exec extension host to open an unbounded number of file descriptors.

In the observed incident, one process grew from 1,826 file descriptors to 106,139 in approximately 16 seconds. Of those, 106,122 were vnode/file descriptors. The system-wide file table was exhausted, Cursor began reporting ENFILE: file table overflow, and macOS eventually restarted with a kernel panic after launchd (PID 1) exited.

The process holding the descriptors was:

Cursor Helper (Plugin): extension-host (agent-exec) <workspace>

The workspace contained approximately:

  • 8,000 tracked files in the main checkout
  • 1,802 agent-* directories below .claude/worktrees/
  • 299 registered secondary Git worktrees
  • approximately 1,500 stale or partial worktree directories without matching Git worktree metadata

Some successful worktree checkouts contained approximately 8,000 files each. This is an unusually large directory tree, but scanning it should not cause file descriptors to remain open or exhaust the system-wide file table.

Sanitized monitoring data from the incident:

19:37:50  global_file_objects=11,703
19:37:50  pid=<agent-exec> fd_count=1,826 vnode=1,817

19:38:06  global_file_objects=117,226
19:38:06  pid=<agent-exec> fd_count=106,139 vnode=106,122

At the same time, Cursor logged repeated errors for different files inside the worktree tree:

[Extension Host:agent-exec] Error processing .gitignore file at
/Users/<redacted>/workspace/<repo>/.claude/worktrees/agent-<id>/<path>/.gitignore:
Error: ENFILE: file table overflow, open '<redacted>/.gitignore'

Error: ENFILE: file table overflow, spawn ps

The subsequent macOS panic contained:

initproc exited -- exit reason namespace 2 subcode 0xa
Panicked task ... pid 1: launchd

This is not a per-process EMFILE condition. It is a system-wide ENFILE condition, so increasing ulimit -n is not an effective fix and may allow the process to consume even more kernel resources before failing.

The accumulated worktrees were created by another development tool and are a trigger/precondition, not necessarily a Cursor-created artifact. The Cursor-specific bug is that agent-exec appears to retain, or concurrently open without a safe bound, more than 100,000 vnode descriptors while processing the tree.

Steps to Reproduce

Warning: the full reproduction can exhaust the macOS system-wide file table and force a restart. It should only be attempted in a disposable or otherwise controlled environment.

  1. Start with a Git repository containing approximately 8,000 files.
  2. Create a large directory tree at .claude/worktrees/ containing many worktree-style checkouts or partial checkouts. The observed case had 1,802 top-level agent-* directories, with many nested .gitignore files.
  3. Do not exclude .claude/worktrees/ from the workspace.
  4. Open the repository root in Cursor.
  5. Monitor Cursor Helper processes using lsof -p <pid> or another per-process FD counter.
  6. Identify the helper whose command line contains extension-host (agent-exec).
  7. Observe the vnode FD count while Cursor processes the workspace.

Observed result: the agent-exec helper’s vnode count rises extremely rapidly and does not return to baseline. Cursor then emits ENFILE errors while processing .gitignore files. In the full-scale case, the count exceeded 106,000 and caused a macOS kernel panic.

A safer engineering reproduction would use progressively larger synthetic trees and stop Cursor as soon as the agent-exec FD count begins growing monotonically.

Expected Behavior

Cursor should bound the number of concurrent file operations and close every file/directory descriptor on success, failure, cancellation, and ignore-file parsing errors.

For an excessively large workspace, Cursor should either:

  • scan it with a bounded and stable FD count,
  • skip nested worktree storage directories,
  • honor an exclusion before traversing the directory, or
  • stop scanning and report a recoverable workspace-size error.

It should never exhaust the system-wide file table or destabilize the operating system.

Operating System

MacOS

Version Information

Cursor: 3.13.10 (Stable)
Commit: 4f02290ccd9304f0e6bf8ee85f6e9106f02ac1f0
Build date: 2026-07-23T21:41:07.333Z
Electron: 40.10.3
Chromium: 144.0.7559.236
V8: 14.4.258.32-electron.0
OS: macOS 26.6 (25G72), arm64

Does this stop you from using Cursor

Yes - Cursor is unusable

Hey, thanks for the detailed report. The FD growth logs, panic trace, and exact numbers really help.

This is a bug on our side. When we walk the workspace, the ignore-file scan doesn’t limit how many file descriptors it opens at once, and on a worktree this large it hits the system-wide file table. You’re right that ulimit -n won’t help here. This is system-wide ENFILE, not per-process EMFILE. I’ve filed it internally, but I can’t share a fix timeline yet.

A working workaround for now is to exclude the worktree directory before the walker reaches it. Add .claude/worktrees/ to the repo .gitignore (or to .git/info/exclude if you don’t want to commit it). The discovery walk respects VCS ignore rules, so it won’t descend into that folder. If the worktrees are stale or broken, you can also just delete them.

Important: .cursorignore won’t help in this case (its rules don’t apply to the discovery walk that finds those files), and files.watcherExclude isn’t the right tool for this path either. Please rely on .gitignore or .git/info/exclude.

Let me know if the workaround helps. I’ll post an update in the thread once we have progress on the fix.