Skip to content

Roslyn LSP causes excessive inotify watches on Linux via .NET FileSystemWatcher #82857

@dibarbet

Description

@dibarbet

Summary

When the Roslyn Language Server runs on Linux, .NET's FileSystemWatcher creates an inotify watch for every subdirectory under each watched path — because Linux's inotify API has no native recursive watch support. Since Roslyn watches ~/.nuget/packages (among other paths) for reference DLL changes, this results in hundreds of thousands of inotify registrations. This exhausts the system's inotify limit and causes VS Code to report constant "unable to watch" warnings across the entire editor.

Note - this is specifically hitting the watch limit, not the instance limit.

Details

The watch on ~/.nuget/packages is registered in FileWatchedReferenceFactory.GetAdditionalWatchedDirectories() to detect changes to referenced DLLs. On Windows, ReadDirectoryChangesW handles recursive watching natively with one OS handle. On Linux, .NET's FileSystemWatcher must create a separate inotify file descriptor for every subdirectory, and the NuGet cache contains thousands of packages with deep directory trees that grow over time as new versions accumulate.

The code already skips this watch on Windows (line 105-108) due to concerns about overhead during restore.

Observed scale (Fred's machine)

  • ~308,000 directory watches in ~/.nuget/packages
  • ~470,000 total watches from the LSP process
  • Top packages by watch count: microsoft.codeanalysis.common (5,766), microsoft.codeanalysis.workspaces.common (5,368), microsoft.codeanalysis.csharp (5,194)
  • The NuGet cache contained 60+ versions of some packages (e.g. microsoft.codeanalysis.common)

Suggestions from discussion

  1. Consolidate watched directories with a cap: Maintain a list of watched directories with a maximum count (e.g. 10). When adding a new watch, check if it's already contained by an existing directory watcher. If not, check if it contains any existing watches and consolidate. Start the list seeded with the home directory. When too many leaf watches accumulate, consolidate upward to a common ancestor. This bounds inotify usage regardless of how many paths Roslyn needs to observe.

  2. Wait for .NET 11 improvements: FileSystemWatching on non-Windows is expected to improve in .NET 11, but the Roslyn LSP runs as a dotnet tool and likely needs to target LTS versions, so this isn't a near-term solution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-IDELSPissues related to the roslyn language server protocol implementation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions