On an interactive server circuit, NavigationManager.NavigateTo(uri) sends the browser a JS call from the framework's own fire-and-forget task and awaits the acknowledgement. When the circuit's connection drops first, the circuit is kept for reconnection, so it is not yet permanently disconnected, and the framework's quiet path for a disconnected circuit does not apply. The JS-interop call timeout cancels the call a minute later. The framework then logs Navigation failed when changing the location to … and raises the cancellation as unhandled, which the circuit host logs as CircuitHost[111] Unhandled exception in circuit and answers by ending the circuit. The task is the framework's, so no caller can catch it (MeshWeaver#5362).

Measured on 2026-10-23: two recurrences, on two pods, went to /ReinsuranceDemo/Subscribe and /SST/Subscribe. That is the paywall a gated page redirects an unentitled viewer to (PluginGate sets the plugin's RedirectOnDenied, and NamedAreaView renders a RedirectControl). RedirectView issued that redirect from a data emission, at a browser whose connection may already have dropped. The earlier full-page shapes are covered by links that leave the app (FullPageNavigation.LeaveTo).

The fix

InCircuitNavigation.NavigateWithin (MeshWeaver.Blazor) asks the browser itself through Blazor.navigateTo, the browser-side entry of the same navigation, which still consults the circuit's location-changing handlers. It then classifies how that call ended against the circuit's own connection record, ICircuitConnection. That record is fed by CircuitConnection, a scoped CircuitHandler in MeshWeaver.Hosting.Blazor that counts every OnConnectionDown and tracks the current state.

The call ended… and the connection… logged as
acknowledged anything nothing
JSDisconnectedException (the circuit is gone) anything Debug
cancelled was down when the call was issued, dropped while it was pending (even if it came back), or is down now Information, and the navigation is issued again when the connection is restored (see below)
cancelled stayed up the whole time Error: a live browser did not answer within the call timeout
cancelled is not reported by the host Error: no evidence of a disconnect
any other failure (JSException …) anything Error

None of these ends the circuit.

A lost navigation is issued again on reconnection. The framework used to end the circuit, so a reconnecting browser reloaded and the redirect ran again. Now the circuit is kept, and a navigation the browser never received must still reach it. Otherwise a viewer who reconnects stays on a page that renders nothing but the redirect. The helper waits for ICircuitConnection.Restored (or goes at once if the connection is already back) and sends the same navigation again, unless it was superseded first:

A circuit that ends without reconnecting completes Restored, and nothing is sent.

Ticket and send are one navigation turn (ICircuitConnection.NavigationTurn, a plain monitor over synchronous work only: a turn sends the call and returns, and never awaits the answer). A fresh navigation takes its ticket and is sent in one turn. A replay checks its ticket and is sent in one turn. A newer navigation therefore cannot be sent between a replay's check and its send, and the newest destination always reaches the browser last. A location move made by the viewer comes from the browser and is not serialized by the turn. The replay reads it as late as it can.

An empty URI means the application base, as it does for NavigationManager.NavigateTo(""). A statically rendered component has no browser to call, so it keeps the framework's navigation (an HTTP redirect), synchronously.

Routed through it: RedirectView, ButtonView's NavigateToHref and NavigateOnAccepted, and NavigationService.NavigateTo for an in-app (non-forceLoad) navigation. Other direct NavigationManager.NavigateTo calls are not migrated yet. They still take the framework's call, mostly from user clicks where the race window is a single round trip.

Proof

InCircuitNavigationTest (MeshWeaver.Hosting.Blazor.Test):

BoundRedirectNavigatesTest.AViewerWhoseConnectionDropped_IsNotAnUnhandledCircuitException (MeshWeaver.Blazor.Views.Test) renders a real RedirectView. It fails when RedirectView calls NavigationManager.NavigateTo, because the redirect then reaches the framework's navigation and not the browser. ARedirectLostToADroppedConnection_ReachesTheBrowserWhenItReconnects renders the same view through a drop and a reconnection.