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
- Inspect the server-side negotiate response chain (log the `url` field of each response) to find the loop.
- Fix the reverse proxy to preserve the original Host/path so redirects resolve absolutely.
- Ensure sticky sessions or a proper backplane so the server doesn't keep redirecting.
- 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
- Ensure your reverse proxy preserves Host and path so redirects resolve absolutely.
- Validate Azure SignalR Service endpoint configuration.
- Log negotiate responses at Information level during staging to detect redirect cycles.
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
- Negotiation can only be skipped when using the WebSocket tra
- The connection was stopped during negotiation.
- Detected a connection attempt to an ASP.NET SignalR Server.
- Unexpected status code returned from negotiate: %d %s.
- Negotiation can only be skipped when using the WebSocket tra
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/133fd2b56afdb61f.
Report an issue: GitHub.