{"record":{"id":"4cb6f1725e4469d0","repo":"dotnet/aspnetcore","slug":"negotiateresponse-geterror","errorCode":null,"errorMessage":"${negotiateResponse.getError()}","messagePattern":"\\$\\{negotiateResponse\\.getError\\(\\)\\}","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java","lineNumber":184,"sourceCode":"        this.keepAliveInterval = keepAliveInterval;\n\n        this.callback = (payload) -> ReceiveLoop(payload);\n    }\n\n    private Single<NegotiateResponse> handleNegotiate(String url, Map<String, String> localHeaders) {\n        HttpRequest request = new HttpRequest();\n        request.addHeaders(localHeaders);\n\n        return httpClient.post(Negotiate.resolveNegotiateUrl(url, this.negotiateVersion), request).map((response) -> {\n            if (response.getStatusCode() != 200) {\n                throw new HttpRequestException(String.format(\"Unexpected status code returned from negotiate: %d %s.\",\n                        response.getStatusCode(), response.getStatusText()), response.getStatusCode());\n            }\n            JsonReader reader = new JsonReader(new StringReader(new String(response.getContent().array(), StandardCharsets.UTF_8)));\n            NegotiateResponse negotiateResponse = new NegotiateResponse(reader);\n\n            if (negotiateResponse.getError() != null) {\n                throw new RuntimeException(negotiateResponse.getError());\n            }\n\n            if (negotiateResponse.getAccessToken() != null) {\n                localHeaders.put(\"Authorization\", \"Bearer \" + negotiateResponse.getAccessToken());\n            }\n\n            return negotiateResponse;\n        });\n    }\n\n    /**\n     * Indicates the state of the {@link HubConnection} to the server.\n     *\n     * @return HubConnection state enum.\n     */\n    public HubConnectionState getConnectionState() {\n        return this.state.getHubConnectionState();\n    }","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java#L166-L202","documentation":"Thrown inside handleNegotiate when a 200 negotiate response carries a non-null error string in its JSON body. The server answered the negotiate POST successfully (HTTP 200) but populated the 'error' field, indicating it could not complete negotiation - typically because the negotiate version is unsupported or the connection is unauthorized at the app layer.","triggerScenarios":"NegotiateResponse.getError() returns a value after the 200 check passed. The server's /negotiate returned 200 with an error JSON field; the client rethrows that error verbatim as a RuntimeException.","commonSituations":"Client and server negotiateVersion mismatch (client sends v1, server only supports v0 or vice versa); the server rejected the connection at the application layer (auth policy, IUserIdProvider); a transient server-side error during negotiate payload construction.","solutions":["Surface negotiateResponse.getError() to logs - it is the server's own explanation and the fastest path to root cause.","Confirm client and server negotiate versions are compatible (the client hardcodes negotiateVersion = 1; ensure the server supports it).","Check server-side auth/authorization on the hub endpoint and that the connection carries required claims.","Reproduce with curl: POST {hub}/negotiate with the same headers and inspect the JSON error field."],"exampleFix":"// before: client forces negotiateVersion the server rejects\n// server replies 200 { \"error\": \"Unsupported negotiate version.\" }\n\n// after: align versions - update the server (ASP.NET Core) or client to a matching release,\n// and verify the hub endpoint allows the caller.","handlingStrategy":"try-catch","validationCode":"// No client validation prevents a server-side error payload.\n// Before start(), confirm client/server negotiateVersion compatibility from your deployment matrix.\nboolean versionsCompatible = true; // from compatibility matrix","typeGuard":"// Server-supplied error string cannot be type-guarded client-side.\n// Capture and inspect NegotiateResponse.getError() in logs.","tryCatchPattern":"try {\n  conn.start().blockingAwait();\n} catch (RuntimeException e) {\n  String msg = e.getMessage();\n  if (msg != null && !msg.contains(\"status code\") && !msg.contains(\"negotiate\")) {\n    // likely the server's negotiate error string - log and reconcile version/auth\n  } else throw e;\n}","preventionTips":["Keep client negotiateVersion compatible with the server (this client uses v1).","Check hub endpoint auth/authorization policies.","Reproduce POST {hub}/negotiate with curl and inspect the JSON error field."],"tags":["signalr","java","network","negotiate","server-error"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}