dotnet/aspnetcore · warning · AbortError
The connection was stopped during negotiation.
Error message
The connection was stopped during negotiation.
What it means
Wrapped in AbortError at HttpConnection.ts:272 inside the negotiate loop of _startInternal. It fires when the connection state transitions to Disconnecting or Disconnected between negotiate round-trips, meaning `stop()` was called while a negotiate POST was still in flight. This is a deliberate race-resolution signal rather than a bug; the in-flight start promise rejects with this AbortError so callers awaiting `start()` observe the cancellation.
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 294cab2f9b)
Solutions
- Treat AbortError specially in your start() catch handler — log and ignore it rather than surfacing as a hard failure.
- Guard stop() calls with a check of connection.state so you don't interrupt an in-flight start.
- In tests/unmount, await the start() promise (or race it with a timeout) before issuing stop().
Example fix
// before
try { await hub.start(); } catch (e) { console.error("start failed", e); }
// after
try { await hub.start(); } catch (e) {
if (e instanceof AbortError || /stopped during negotiation/i.test(e.message)) {
return; // expected when stop() raced start()
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// no pre-check possible — the race is between start() and stop(). // Just ensure you only call stop after start has resolved.
Type guard
function isAbortDuringNegotiate(e: unknown): boolean {
return e instanceof AbortError && /stopped during negotiation/i.test(String((e as Error).message));
} Try / catch
try {
await hub.start();
} catch (e) {
if (e instanceof AbortError && /stopped during negotiation/i.test(e.message)) {
// expected cancellation — ignore
return;
}
throw e;
} Prevention
- Don't call stop() in onclose handlers re-entrantly during start.
- In component unmount, await start() (or race with timeout) before issuing stop().
- Differentiate AbortError from real failures in your start catch handler.
When it happens
Trigger: Calling `connection.stop()` (or `hubConnection.stop()`) while `start()` is still awaiting the negotiate HTTP response; navigating away or closing the tab during the brief negotiate window; a reconnect attempt that is itself cancelled mid-negotiate.
Common situations: User navigates away or logs out immediately after connecting; an `onclose` handler that calls `stop()` re-entrantly; React/SPA unmount racing the connection start; tests that tear down a connection before start resolves.
Related errors
- No interop methods are registered for renderer ${rendererId}
- Cannot connect component ${this.localName} to the document a
- Blazor WebAssembly has not initialized.
- Cannot start a disposed circuit.
- The circuit associated with this dispatcher is no longer ava
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/9e102d9e2daf8085.
Report an issue: GitHub.