{"record":{"id":"6c72b325a6269b99","repo":"dotnet/aspnetcore","slug":"error-reading-negotiateresponse","errorCode":null,"errorMessage":"Error reading NegotiateResponse","messagePattern":"Error reading NegotiateResponse","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/NegotiateResponse.java","lineNumber":86,"sourceCode":"                                this.availableTransports.add(transport);\n                            }\n                            reader.endObject();\n                        }\n                        reader.endArray();\n                        break;\n                    case \"connectionId\":\n                        this.connectionId = reader.nextString();\n                        break;\n                    default:\n                        // Skip unknown property, allows new clients to still work with old protocols\n                        reader.skipValue();\n                        break;\n                }\n            } while (reader.hasNext());\n            reader.endObject();\n            reader.close();\n        } catch (IOException ex) {\n            throw new RuntimeException(\"Error reading NegotiateResponse\", ex);\n        }\n    }\n\n    public NegotiateResponse(String url) {\n        this.finalUrl = url;\n    }\n\n    public String getConnectionId() {\n        return connectionId;\n    }\n\n    public Set<String> getAvailableTransports() {\n        return availableTransports;\n    }\n\n    public String getRedirectUrl() {\n        return redirectUrl;\n    }","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/NegotiateResponse.java#L68-L104","documentation":"NegotiateResponse parses the JSON body returned by the /negotiate POST. Any IOException while reading the stream (malformed JSON, premature EOF, network read failure mid-parse) is wrapped in a RuntimeException with the generic message. The parser does skip unknown properties for forward compatibility, so only genuine parse/stream errors reach this catch.","triggerScenarios":"The /negotiate endpoint returns non-JSON (HTML error page, empty body, gateway 502); truncated response due to connection drop; charset/encoding mismatch; the negotiate endpoint is hosted behind a proxy that rewrote the body.","commonSituations":"Reverse proxy (nginx/HAProxy) returning an HTML 502/503 instead of JSON; Azure SignalR negotiate going to a stale backend; server returning a redirect HTML page; auth layer returning a login HTML page because the bearer token was rejected.","solutions":["curl -i the /negotiate URL with the same auth headers and inspect the raw body and status code.","Ensure the hub endpoint is reachable and returns application/json; fix reverse proxy to pass through negotiate responses.","Verify the access token / auth is accepted - a 401 HTML login page will fail to parse as JSON."],"exampleFix":"// before\nHubConnection hub = HubConnectionBuilder.create(\"https://app/hub\").build();\nhub.start(); // negotiate returns HTML -> parse error\n\n// after - verify negotiate returns JSON\n// curl -i -H \"Authorization: Bearer ...\" https://app/hub/negotiate\n// must return 200 { \"connectionId\":..., \"availableTransports\":[...] }\nHubConnection hub = HubConnectionBuilder.create(\"https://app/hub\")\n    .withAccessTokenProvider(...)\n    .build();\nhub.start();","handlingStrategy":"validation","validationCode":"// Pre-flight: confirm negotiate returns JSON before starting the hub.\nResponse r = httpClient.post(url + \"/negotiate\", authHeaders);\nif (r.contentType() == null || !r.contentType().contains(\"json\")) {\n  throw new IllegalStateException(\n    \"Negotiate did not return JSON; status=\" + r.statusCode()\n    + \" bodyPrefix=\" + r.body().substring(0, Math.min(80, r.body().length())));\n}","typeGuard":null,"tryCatchPattern":"hub.onClosed(ex -> {\n  if (ex != null && ex.getMessage().contains(\"Error reading NegotiateResponse\")) {\n    // likely HTML from proxy/auth; log negotiate response, fix infra, retry\n  }\n});","preventionTips":["Add a /negotiate health check to your deployment smoke test.","Verify auth tokens are accepted before relying on negotiate.","Ensure reverse proxies pass through JSON negotiate bodies unchanged."],"tags":["signalr","java","negotiate","json","network","parsing"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}