dotnet/aspnetcore · error · RuntimeException

Error reading NegotiateResponse

Error message

Error reading NegotiateResponse

What it means

Thrown when the Gson JsonReader hits an IOException while parsing the negotiate HTTP response (malformed JSON, an unexpected token type such as nextString() on a number, a truncated stream, or a network read failure mid-parse). The raw IOException is wrapped in a RuntimeException because the NegotiateResponse constructor does not declare checked exceptions.

Source

Thrown at src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/NegotiateResponse.java:86

                                this.availableTransports.add(transport);
                            }
                            reader.endObject();
                        }
                        reader.endArray();
                        break;
                    case "connectionId":
                        this.connectionId = reader.nextString();
                        break;
                    default:
                        // Skip unknown property, allows new clients to still work with old protocols
                        reader.skipValue();
                        break;
                }
            } while (reader.hasNext());
            reader.endObject();
            reader.close();
        } catch (IOException ex) {
            throw new RuntimeException("Error reading NegotiateResponse", ex);
        }
    }

    public NegotiateResponse(String url) {
        this.finalUrl = url;
    }

    public String getConnectionId() {
        return connectionId;
    }

    public Set<String> getAvailableTransports() {
        return availableTransports;
    }

    public String getRedirectUrl() {
        return redirectUrl;
    }

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Verify the negotiate URL returns a JSON object containing connectionId/availableTransports.
  2. Confirm you are targeting an ASP.NET Core SignalR hub, not legacy ASP.NET.
  3. Inspect the actual negotiate response body with curl/Postman and fix any proxy truncation.
  4. Ensure no auth redirect or error page intercepts the negotiate request.

Example fix

// diagnose before fixing client code:
// curl -i -X POST https://host/hub/negotiate  -H 'Content-Length: 0'
// expect: {"connectionId":"...","availableTransports":[...]}
Defensive patterns

Strategy: try-catch

Try / catch

// Java - start() propagates the wrapped RuntimeException
hubConnection.start().subscribe(
    () -> { /* connected */ },
    error -> {
        if (error.getMessage() != null && error.getMessage().contains("NegotiateResponse")) {
            // inspect server /negotiate endpoint, proxies, auth redirects
        }
    });

Prevention

When it happens

Trigger: Server returns non-JSON or a partial body to the /negotiate POST; a field arrives as the wrong JSON type; connection drops during negotiate read; an auth redirect returns HTML instead of JSON.

Common situations: Connecting through a reverse proxy/gateway that strips or truncates the negotiate response; pointing at a non-SignalR endpoint; hitting a legacy ASP.NET (non-Core) server; load balancer returning an HTML error page (502/503); CORS/auth returning HTML.

Related errors


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