dotnet/aspnetcore · critical · Error

Negotiate redirection limit exceeded.

Error message

Negotiate redirection limit exceeded.

What it means

Thrown at HttpConnection.ts:298 when the negotiate loop follows 100 consecutive redirects (MAX_REDIRECTS) and the server is still returning a `url` field. Negotiate redirection is a server feature for load balancing and sharding; a healthy server redirects at most once or twice. Hitting the cap indicates a redirect loop or a misconfigured server that keeps pointing back to itself.

Source

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

                        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++;
                }
                while (negotiateResponse.url && redirects < MAX_REDIRECTS);

                if (redirects === MAX_REDIRECTS && negotiateResponse.url) {
                    throw new Error("Negotiate redirection limit exceeded.");
                }

                const finalNegotiateResponse = await this._createTransport(url, this._options.transport, negotiateResponse, transferFormat);
                this._configureAuthenticationRefresh(finalNegotiateResponse);
            }

            if (this.transport instanceof LongPollingTransport) {
                this.features.inherentKeepAlive = true;
            }

            if (this._connectionState === ConnectionState.Connecting) {
                // Ensure the connection transitions to the connected state prior to completing this.startInternalPromise.
                // start() will handle the case when stop was called and startInternal exits still in the disconnecting state.
                this._logger.log(LogLevel.Debug, "The HttpConnection connected successfully.");
                this._connectionState = ConnectionState.Connected;
            }

            // stop() is waiting on us via this.startInternalPromise so keep this.transport around so it can clean up.

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Inspect the server-side negotiate response chain (log the `url` field of each response) to find the loop.
  2. Fix the reverse proxy to preserve the original Host/path so redirects resolve absolutely.
  3. Ensure sticky sessions or a proper backplane so the server doesn't keep redirecting.
  4. If using Azure SignalR, verify the connection string / endpoint configuration is not pointing back to the app.

Example fix

// server (ASP.NET Core) - ensure negotiate does not self-redirect
// app.MapHub<MyHub>("/hubs/myhub");  // consistent path

// client - log redirects to diagnose
const conn = new HttpConnection(url, {
  logger: LogLevel.Information,
});
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot pre-check client-side; the redirect chain is server-driven.
// Instrument the negotiate responses in a custom logger to detect loops early.

Try / catch

try { await hub.start(); }
catch (e) {
  if (/Negotiate redirection limit exceeded/.test(String(e))) {
    // surface to ops: server-side redirect loop
    reportToOps('signalr-negotiate-loop', e);
  }
  throw e;
}

Prevention

When it happens

Trigger: A backend/sticky-session LB misconfiguration where the negotiate endpoint at server A returns a url pointing to server B, whose negotiate returns A again; an Azure SignalR Service or backplane configured with a self-referencing redirect; a proxy rewriting the negotiate URL incorrectly.

Common situations: Misconfigured Azure SignalR Service with multiple endpoints looping; reverse proxy (Nginx/HAProxy) rewriting the Host header such that the absolute redirect URL re-enters negotiation; custom middleware that always appends a redirect; cyclic appService routing.

Related errors


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