dotnet/aspnetcore · warning · AbortError
The connection was stopped during negotiation.
Error message
The connection was stopped during negotiation.
What it means
During the negotiate loop, after each /negotiate round-trip the client checks _connectionState. If the user called stop() (or the connection was otherwise torn down) while negotiation was in flight, the state is Disconnecting/Disconnected and the client throws AbortError to abandon startup cleanly.
Solutions
- Treat AbortError specially in your start() catch block and do not surface it as a real error.
- Avoid calling stop() until start() has resolved; gate stop() on the start promise.
- If you must support stop-during-start, swallow AbortError silently in the UI.
Example fix
// before
const startPromise = connection.start();
// user cancels immediately
connection.stop();
await startPromise; // throws AbortError
// after
const startPromise = connection.start();
await startPromise;
// only stop after start resolved
await connection.stop();
// or, in the catch:
try { await connection.start(); }
catch (e) {
if (e instanceof signalR.AbortError) return; // expected on cancel
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
let startPromise: Promise<void> | null = null;
async function safeStart(conn: signalR.HubConnection) {
startPromise = conn.start();
await startPromise;
startPromise = null;
}
async function safeStop(conn: signalR.HubConnection) {
if (startPromise) await startPromise.catch(() => {});
await conn.stop();
} Type guard
import { AbortError } from "@microsoft/signalr";
function isAbortError(e: unknown): e is AbortError { return e instanceof AbortError; } Try / catch
import { AbortError } from "@microsoft/signalr";
try { await connection.start(); }
catch (e) {
if (e instanceof AbortError) return; // expected when stop() raced start()
throw e;
} Prevention
- Await the start() promise before calling stop().
- Treat AbortError as expected during cancellation flows.
- Use a single state machine for connection lifecycle to avoid start/stop races.
When it happens
Trigger: User calls connection.stop() (or start() was racing with a stop) while HttpConnection is still waiting on the negotiate HTTP response. Also possible if the underlying connection silently disconnected and the state machine flipped during the await.
Common situations: A 'cancel' button or route-change handler that calls stop() immediately after start() on a slow network. A component unmount in React that aborts the connection mid-handshake. Reactive code that starts and immediately stops the connection based on a flag.
Related errors
- Cannot refresh authentication before the connection is…
- Blazor has already started.
- Blazor has already started.
- Blazor has already started.
- Blazor has already started.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/9e102d9e2daf8085.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/ts/signalr/src/HttpConnection.ts:272
if (this._options.skipNegotiation) {
if (this._options.transport === HttpTransportType.WebSockets) {
// No need to add a connection ID in this case
this.transport = this._constructTransport(HttpTransportType.WebSockets);
// We should just call connect directly in this case.
// No fallback or negotiate in this case.
await this._startTransport(url, transferFormat);
} else {
throw new Error("Negotiation can only be skipped when using the WebSocket transport directly.");
}
} else {
let negotiateResponse: INegotiateResponse | null = null;
let redirects = 0;
do {
negotiateResponse = await this._getNegotiationResponse(url);
// the user tries to stop the connection when it is being started
if (this._connectionState === ConnectionState.Disconnecting || this._connectionState === ConnectionState.Disconnected) {
throw new AbortError("The connection was stopped during negotiation.");
}
if (negotiateResponse.error) {
throw new Error(negotiateResponse.error);
}
if ((negotiateResponse as any).ProtocolVersion) {
throw new Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.");
}
if (negotiateResponse.url) {
url = negotiateResponse.url;
}
if (negotiateResponse.accessToken) {
// Replace the current access token factory with one that uses
// the returned access token
this._setTransportAccessToken(negotiateResponse.accessToken);View on GitHub (pinned to 3600ca084e)