dotnet/aspnetcore · error · Error

negotiateResponse.error

Error message

negotiateResponse.error

What it means

If the /negotiate response body contains an 'error' field, the server is reporting a negotiation failure (e.g. hub not found, protocol unsupported, transport disabled). The client surfaces that server-provided string by throwing new Error(negotiateResponse.error).

Source

Thrown at src/SignalR/clients/ts/signalr/src/HttpConnection.ts:276

                    // 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);
                    }

                    redirects++;
                }

View on GitHub (pinned to 3600ca084e)

Solutions

  1. Read the actual error string — it is the server's explanation (e.g. 'The Server was unable to negotiate...').
  2. Verify the hub is registered at the exact route (case-sensitive) the client is hitting.
  3. Confirm at least one transport the client allows is enabled on the server (ConfigureKestrel/AddSignalR options).
  4. For Azure SignalR, check the connection string and that the endpoint is reachable.

Example fix

// before
try { await connection.start(); }
catch (e) { console.error(e); }

// after — surface the server error verbosely
try { await connection.start(); }
catch (e) {
  if (typeof e.message === "string" && e.message.length)
    console.error("Negotiate error from server:", e.message);
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: hit negotiate and surface the server's error
async function probeNegotiate(url: string) {
  const r = await fetch(`${url}/negotiate?negotiateVersion=1`, { method: "POST" });
  const body = await r.json();
  if (body.error) throw new Error(`Server negotiate error: ${body.error}`);
  return body;
}

Type guard

function hasNegotiateError(v: unknown): v is { error: string } {
  return typeof v === "object" && v !== null && typeof (v as any).error === "string";
}

Try / catch

try { await connection.start(); }
catch (e) {
  const msg = (e instanceof Error && e.message) || "";
  // The message IS the server-provided error string; log it for diagnosis
  console.error("Server returned negotiate error:", msg);
  throw e;
}

Prevention

When it happens

Trigger: Any 200 negotiate response whose JSON contains an error string. The server's NegotiateMiddleware or hub endpoint wrote an error: "..." into the response. Causes include unknown hub, disallowed transport, invalid protocol, or a custom IConnection that rejects negotiation.

Common situations: Hub route typo (negotiate returns error indicating no hub). Server config disables all transports the client requested. Azure SignalR Service misconfigured (wrong endpoint/key yields an error in negotiate). ConnectionId could not be generated.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/856d2a7df26e31e5. Report an issue: GitHub.