dotnet / dotnet/sdk

'dotnet watch' crashes with StackOverflowException on macOS when watching large solution

Open
#53,754 1 comment 0 reactions 1 assignee Claimed by @tmat View on GitHub
Area-Watch
Dominant language
C#
Stars
3.2k
Forks
1.3k
PR merge metrics
PR metrics pending

Description

### Describe the bug
`dotnet watch` crashes with a stack overflow on macOS (15.7.5) when used with a large solution containing ~200 projects (including a Git submodule with 192+ projects). The build and project loading complete successfully, but the process crashes immediately when the hot reload file watcher starts.

This worked on .NET 8. The crash started after upgrading to .NET 10 SDK (10.0.201).

### To Reproduce

1. On macOS (tested on Sequoia 15.7.5, Apple Silicon)
2. Have a large .NET 10 solution with ~200+ projects
3. Run `dotnet watch` on the solution's entry project
4. Build completes, projects load successfully
5. Process crashes with stack overflow when hot reload file watching starts

### Exceptions (if any)

```
Stack overflow.
Repeated 25 times:
--------------------------------
at System.IO.FileSystemWatcher.StartRaisingEvents()
at Microsoft.DotNet.Watch.EventBasedDirectoryWatcher.CreateFileSystemWatcher()
at System.IO.FileSystemWatcher.OnError(System.IO.ErrorEventArgs)
at System.IO.FileSystemWatcher+RunningInstance.Start(System.Threading.CancellationToken)
--------------------------------
at System.IO.FileSystemWatcher.StartRaisingEvents()
at Microsoft.DotNet.Watch.EventBasedDirectoryWatcher.CreateFileSystemWatcher()
at Microsoft.DotNet.Watch.EventBasedDirectoryWatcher.WatcherErrorHandler(System.Object, System.IO.ErrorEventArgs)
...
at Microsoft.DotNet.Watch.EvaluationResult.WatchFiles(Microsoft.DotNet.Watch.FileWatcher)
at Microsoft.DotNet.Watch.HotReloadDotNetWatcher+d__12.MoveNext()
```

## Possible Fix directions

I let claude look at a diff between Dotnet 8 and Dotnet 10 in regard to this issue. Take the following with a grain of salt.

Looking at the stack trace, the immediate crash mechanism appears to be a recursive error handler in [`EventBasedDirectoryWatcher.WatcherErrorHandler`](https://github.com/dotnet/sdk/blob/main/src/Dotnet.Watch/Watch/FileWatcher/EventBasedDirectoryWatcher.cs):

```csharp
private void WatcherErrorHandler(object sender, ErrorEventArgs e)
{
var exception = e.GetException();

// Win32Exception may be triggered when setting EnableRaisingEvents on a file system type
// that is not supported, such as a network share. Don't attempt to recreate the watcher
// in this case as it will cause a StackOverflowException
if (exception is not Win32Exception)
{
// Recreate the watcher if it is a recoverable error.
CreateFileSystemWatcher();
}
}
```

It looks like `FileSystemWatcher.StartRaisingEvents()` fails on macOS, and the error handler calls `CreateFileSystemWatcher()`, which sets `EnableRaisingEvents = enableEvents` (preserving the previous `true` state), which calls `StartRaisingEvents()`, which fails again, triggering the error handler again - all synchronously on the same call stack, recursing until the stack overflows.

The guard only checks for `Win32Exception`, but on macOS the error appears to be a different exception type, so it falls through to the recursive retry.

The `EventBasedDirectoryWatcher` code itself hasn't changed meaningfully between .NET 8 and 10, so something in the runtime's `FileSystemWatcher` macOS implementation may now cause `StartRaisingEvents()` to fail where it previously succeeded.

Regardless of the underlying cause, it seems like `WatcherErrorHandler` shouldn't synchronously call `CreateFileSystemWatcher()` in a way that can recurse unboundedly. Some ideas:

1. **Add a retry limit or backoff** - e.g., retry once asynchronously after a delay instead of synchronously on the same call stack.
2. **Broaden the exception guard** - don't retry on any exception during `StartRaisingEvents()`, not just `Win32Exception`.

### Further technical details

details of dotnet --info


Version: 10.0.201
Commit: 4d3023de60
Workload version: 10.0.200-manifests.0793c108
MSBuild version: 18.3.0-release-26153-122+4d3023de6

Runtime Environment:
OS Name: Mac OS X
OS Version: 15.7
OS Platform: Darwin
RID: osx-arm64
Base Path: /usr/local/share/dotnet/sdk/10.0.201/

VS CODE Version:

Version: 1.114.0 (Universal)
Commit: e7fb5e96c0730b9deb70b33781f98e2f35975036
Date: 2026-04-01T09:27:11Z (1 wk ago)
Electron: 39.8.3
ElectronBuildId: 13658728
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Darwin arm64 24.6.0

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.