{"record":{"id":"66c6120675ffcf1f","repo":"dotnet/aspnetcore","slug":"there-were-no-compatible-transports-on-the-server","errorCode":null,"errorMessage":"There were no compatible transports on the server.","messagePattern":"There were no compatible transports on the server\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java","lineNumber":385,"sourceCode":"    private Single<NegotiateResponse> startNegotiate(String url, int negotiateAttempts, Map<String, String> localHeaders) {\n        if (this.state.getHubConnectionState() != HubConnectionState.CONNECTING) {\n            throw new RuntimeException(\"HubConnection trying to negotiate when not in the CONNECTING state.\");\n        }\n\n        return handleNegotiate(url, localHeaders).flatMap(response -> {\n            if (response.getRedirectUrl() != null && negotiateAttempts >= MAX_NEGOTIATE_ATTEMPTS) {\n                throw new RuntimeException(\"Negotiate redirection limit exceeded.\");\n            }\n\n            if (response.getRedirectUrl() == null) {\n                Set<String> transports = response.getAvailableTransports();\n                if (this.transportEnum == TransportEnum.ALL) {\n                    if (transports.contains(\"WebSockets\")) {\n                        response.setChosenTransport(TransportEnum.WEBSOCKETS);\n                    } else if (transports.contains(\"LongPolling\")) {\n                        response.setChosenTransport(TransportEnum.LONG_POLLING);\n                    } else {\n                        throw new RuntimeException(\"There were no compatible transports on the server.\");\n                    }\n                } else if (this.transportEnum == TransportEnum.WEBSOCKETS && !transports.contains(\"WebSockets\") ||\n                        (this.transportEnum == TransportEnum.LONG_POLLING && !transports.contains(\"LongPolling\"))) {\n                    throw new RuntimeException(\"There were no compatible transports on the server.\");\n                } else {\n                    response.setChosenTransport(this.transportEnum);\n                }\n\n                String connectionToken = \"\";\n                if (response.getVersion() > 0) {\n                    this.state.getConnectionState().connectionId = response.getConnectionId();\n                    connectionToken = response.getConnectionToken();\n                } else {\n                    connectionToken = response.getConnectionId();\n                    this.state.getConnectionState().connectionId = connectionToken;\n                }\n\n                String finalUrl = Utils.appendQueryString(url, \"id=\" + connectionToken);","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java#L367-L403","documentation":"A RuntimeException thrown by startNegotiate when the client requested TransportEnum.ALL but the server's availableTransports list contains neither 'WebSockets' nor 'LongPolling'. With ALL, the client prefers WebSockets then falls back to LongPolling; if neither is advertised the connection cannot be established.","triggerScenarios":"During start(), after negotiate returns a non-redirect response, the client inspects response.getAvailableTransports(). If the set lacks both 'WebSockets' and 'LongPolling' and transportEnum == ALL, this error is thrown.","commonSituations":"Server only advertises Server-Sent Events or another transport the Java client doesn't implement. ASP.NET Core server configured to disable WebSockets and LongPolling (e.g. only WebSockets enabled but the server is behind a proxy that strips it from the list). Version/protocol mismatch where transport names differ. A non-SignalR endpoint returning a JSON body that parses as a negotiate response but lists no recognizable transports.","solutions":["Inspect the negotiate response's availableTransports field to see what the server actually advertises.","Enable WebSockets (and/or LongPolling) on the ASP.NET Core server (ConfigureKestrel / AddSignalR options).","Ensure the reverse proxy passes through WebSockets so the server includes it in availableTransports.","Verify the base URL points to a real SignalR hub endpoint, not a generic JSON endpoint."],"exampleFix":"// server (ASP.NET Core): ensure WebSockets are available\n// before: only SSE enabled server-side\n// after: enable WebSockets in Kestrel + IIS/nginx\nservices.AddSignalR();\n// program.cs / kestrel: ConfigureKestrel(o => o.AllowSynchronousIO = true) and enable WebSockets middleware\napp.UseWebSockets();","handlingStrategy":"validation","validationCode":"// Probe negotiate to see available transports before committing to start().\nNegotiateResponse r = probeNegotiate(url);\nSet<String> t = r.getAvailableTransports();\nif (!t.contains(\"WebSockets\") && !t.contains(\"LongPolling\")) {\n    throw new IllegalStateException(\"No compatible transports: \" + t);\n}","typeGuard":null,"tryCatchPattern":"connection.start().subscribe(onComplete, error -> {\n    if (error.getMessage().contains(\"no compatible transports\")) {\n        // check server config: enable WebSockets/LongPolling, fix proxy\n    }\n});","preventionTips":["Ensure the ASP.NET Core server enables at least WebSockets or LongPolling.","Configure the reverse proxy to pass WebSocket upgrades so the server advertises WebSockets.","Verify the base URL targets a real SignalR hub, not a generic endpoint.","Log availableTransports from the negotiate response for diagnostics."],"tags":["signalr","java","transport","negotiate","server-configuration","websocket"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}