dotnet watch: Mac Catalyst hot-reload agent WebSocket drops before the first edit; updates fail but watch reports "changes applied"
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 1.3k
- PR merge metrics
- PR metrics pending
Description
## Summary
On Mac Catalyst, `dotnet watch run`'s hot-reload agent connects and negotiates full capabilities at app startup, then its WebSocket connection drops before the first edit arrives. Every subsequent update batch fails with `No active WebSocket connection from the client`, the session gives up (`Further changes won't be applied to this process`) — and `dotnet watch` still reports **`C# and Razor changes applied in 835ms`**, so the failure is invisible unless running with `--verbose`.
Two distinct problems:
1. the agent's WebSocket connection does not survive from startup to the first edit, and there is no reconnect;
2. `dotnet watch` reports success after every update in the batch failed.
## Environment
`macos-latest` GitHub runner (arm64), .NET SDK 10.0.3xx, maui workload set **10.0.302** (i.e. including dotnet/macios#24664, so `StartupHookSupport` defaults to true in Debug and the agent genuinely loads). App: scaffolded MAUI-based Mac Catalyst app, `net10.0-maccatalyst`, Debug, `DOTNET_USE_POLLING_FILE_WATCHER=1`.
Launch is worked around via an explicit `_AppBundleName` override (without it `dotnet run` cannot start a Catalyst app at all when `ApplicationTitle` != `AssemblyName`; filed as dotnet/macios#26318).
## Observed (verbose log, single session)
At startup:
```
dotnet watch : Hot reload session started.
dotnet watch : [App (net10.0-maccatalyst)] WebSocket client connected
dotnet watch : [App (net10.0-maccatalyst)] Capabilities: 'Baseline AddMethodToExistingType AddStaticFieldToExistingType NewTypeDefinition ChangeCustomAttributes AddInstanceFieldToExistingType GenericAddMethodToExistingType GenericUpdateMethod UpdateParameters GenericAddFieldToExistingType AddExplicitInterfaceImplementation'.
dotnet watch : [App (net10.0-maccatalyst)] WebSocket client disconnected
```
On the first (method-body-only) edit, ~1 minute later:
```
dotnet watch : File change: Update '.../MainPage.cs'.
dotnet watch : Hot reload capabilities: ... (full set)
dotnet watch : [App (net10.0-maccatalyst)] Sending update batch #0
dotnet watch : [App (net10.0-maccatalyst)] Update batch #0 failed with error: No active WebSocket connection from the client.
dotnet watch : [App (net10.0-maccatalyst)] Update batch #0 exception stack trace: at Microsoft.DotNet.HotReload.WebSocketClientTransport.RequestHandler.WriteAsync(...)
dotnet watch : [App (net10.0-maccatalyst)] Further changes won't be applied to this process.
dotnet watch : [App (net10.0-maccatalyst)] Disposing agent websocket transport
dotnet watch : C# and Razor changes applied in 835ms.
```
Verified at runtime that nothing was applied: the edit injected a `Console.WriteLine` into a method the app executes every 10 seconds; the new output never appeared over 180s, and the process was not restarted either. Reproduced identically across two independent sessions (with and without an explicit `MtouchInterpreter=all`, which is the Debug default anyway).
## Expected
Either the agent connection stays up for the lifetime of the process (or reconnects), or — failing that — `dotnet watch` reports the update as failed and falls back to its restart path, instead of printing `changes applied`.
The false success seems the more severe half: without `--verbose` the user sees a healthy hot-reload session that silently applies nothing.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.