dotnet / dotnet/sdk

dotnet watch: Mac Catalyst hot-reload agent WebSocket drops before the first edit; updates fail but watch reports "changes applied"

Open
#55,488 4 comments 0 reactions 2 assignees Claimed by @tmat View on GitHub
Area-Watch
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.