SignalR/SignalR · error · InvalidOperationException

Negotiate redirection limit exceeded.

Error message

Negotiate redirection limit exceeded.

What it means

Thrown as InvalidOperationException when the number of negotiate redirects exceeds MaxRedirects (100). SignalR supports redirect responses (RedirectUrl/AccessToken) for scale-out and auth token refresh, but each redirect re-runs negotiation; the limit prevents infinite redirect loops.

Source

Thrown at src/Microsoft.AspNet.SignalR.Client/Connection.cs:581

                                                _actualQueryString = _userQueryString;
                                            }

                                            if (!_actualUrl.EndsWith("/"))
                                            {
                                                _actualUrl += "/";
                                            }

                                            if (!string.IsNullOrEmpty(negotiationResponse.AccessToken))
                                            {
                                                // This will stomp on the current Authorization header, but that's by design.
                                                // If the server specified a token, that is expected to overrule the token the client is currently using.
                                                Headers["Authorization"] = $"Bearer {negotiationResponse.AccessToken}";
                                            }

                                            negotiationAttempts += 1;
                                            if (negotiationAttempts >= MaxRedirects)
                                            {
                                                throw new InvalidOperationException(Resources.Error_NegotiationLimitExceeded);
                                            }
                                            return StartNegotiation();
                                        }
                                    }

                                    return CompleteNegotiation(negotiationResponse);
                                })
                                .ContinueWithNotComplete(() => Disconnect());
            }

            _connectionData = OnSending();

            return StartNegotiation();
        }

        private Task StartTransport()
        {
            return _transport.Start(this, _connectionData, _disconnectCts.Token)

View on GitHub (pinned to 693053b89a)

Solutions

  1. Inspect server-side redirect configuration and the RedirectUrl being returned; ensure it points to a final, non-redirecting endpoint.
  2. Check that the redirect target is stable (not itself emitting a redirect).
  3. Fix proxy/load-balancer rules so they do not redirect negotiate repeatedly.
  4. Verify the auth flow does not force a redirect on every negotiate.

Example fix

// before: server always redirects negotiate back to itself
// after: server returns a stable RedirectUrl only once, then a final negotiation response
Defensive patterns

Strategy: try-catch

Validate before calling

// client cannot pre-validate; ensure server redirect config is stable
// verify RedirectUrl target does not itself redirect

Try / catch

try { await connection.Start(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("redirection limit")) {
    logger.Error("Negotiate redirect loop - check server/RedirectUrl config");
}

Prevention

When it happens

Trigger: The server's negotiate endpoint repeatedly returns a RedirectUrl, causing the client to re-negotiate more than 100 times. Typically a misconfigured redirect target that points back to itself or chains endlessly.

Common situations: A reverse proxy or load balancer that always appends a redirect; a redirect configured to a URL that itself triggers another redirect; auth token refresh logic that always redirects; an incorrect RedirectUrl pointing back to the same negotiate endpoint.

Related errors


AI-assisted analysis of SignalR/SignalR@693053b89a (2026-08-13). Data as JSON: /api/errors/3250ca2bfd8f9e5a. Report an issue: GitHub.