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

  1. Treat AbortError specially in your start() catch handler — log and ignore it rather than surfacing as a hard failure.
  2. Guard stop() calls with a check of connection.state so you don't interrupt an in-flight start.
  3. 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

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


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/9e102d9e2daf8085. Report an issue: GitHub.