{"record":{"id":"5a41e0067102844c","repo":"dotnet/aspnetcore","slug":"detected-a-connection-attempt-to-an-asp-net-signal","errorCode":null,"errorMessage":"Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.","messagePattern":"Detected a connection attempt to an ASP\\.NET SignalR Server\\. This client only supports connecting to an ASP\\.NET Core SignalR Server\\. See https://aka\\.ms/signalr-core-differences for details\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/SignalR/clients/ts/signalr/src/HttpConnection.ts","lineNumber":280,"sourceCode":"                    throw new Error(\"Negotiation can only be skipped when using the WebSocket transport directly.\");\n                }\n            } else {\n                let negotiateResponse: INegotiateResponse | null = null;\n                let redirects = 0;\n\n                do {\n                    negotiateResponse = await this._getNegotiationResponse(url);\n                    // the user tries to stop the connection when it is being started\n                    if (this._connectionState === ConnectionState.Disconnecting || this._connectionState === ConnectionState.Disconnected) {\n                        throw new AbortError(\"The connection was stopped during negotiation.\");\n                    }\n\n                    if (negotiateResponse.error) {\n                        throw new Error(negotiateResponse.error);\n                    }\n\n                    if ((negotiateResponse as any).ProtocolVersion) {\n                        throw new Error(\"Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.\");\n                    }\n\n                    if (negotiateResponse.url) {\n                        url = negotiateResponse.url;\n                    }\n\n                    if (negotiateResponse.accessToken) {\n                        // Replace the current access token factory with one that uses\n                        // the returned access token\n                        this._setTransportAccessToken(negotiateResponse.accessToken);\n                    }\n\n                    redirects++;\n                }\n                while (negotiateResponse.url && redirects < MAX_REDIRECTS);\n\n                if (redirects === MAX_REDIRECTS && negotiateResponse.url) {\n                    throw new Error(\"Negotiate redirection limit exceeded.\");","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/ts/signalr/src/HttpConnection.ts#L262-L298","documentation":"Thrown at HttpConnection.ts:280 when the negotiate response payload contains a `ProtocolVersion` field. ASP.NET (non-Core) SignalR's negotiate response includes ProtocolVersion, whereas ASP.NET Core SignalR does not. This client (the ASP.NET Core JS client) is protocol-incompatible with the older server, so it refuses to continue.","triggerScenarios":"Pointing the @microsoft/signalr client at a server running the legacy ASP.NET SignalR stack (System.Web or Microsoft.AspNet.SignalR) — e.g. an endpoint like `/signalr/negotiate` instead of `/hub/negotiate`. The legacy server returns JSON with a ProtocolVersion key and the guard trips.","commonSituations":"Migrating from ASP.NET to ASP.NET Core but the old endpoint is still deployed; mixing up `/signalr/hubs` (legacy) vs `/hubs/chat` (Core); reading an old tutorial that uses the `jquery.signalR.js` client against a Core server or vice versa; pointing at a misconfigured reverse proxy that routes to the legacy app.","solutions":["Point the client at an ASP.NET Core SignalR hub endpoint (MapHub in Startup.cs/Program.cs), not a legacy ~/signalr endpoint.","If you must talk to a legacy ASP.NET server, use the legacy `jquery.signalR-x.x.x.js` client instead.","Verify the negotiate URL returns Core-style JSON (no ProtocolVersion field).","Check your reverse proxy / load balancer routes to the Core app pool."],"exampleFix":"// before (wrong: legacy endpoint)\nnew HubConnectionBuilder().withUrl('https://app.example.com/signalr').build();\n\n// after (ASP.NET Core hub)\nnew HubConnectionBuilder().withUrl('https://app.example.com/hubs/chat').build();","handlingStrategy":"validation","validationCode":"async function isAspNetCoreHub(url) {\n  const res = await fetch(url.replace(/\\/$/, '') + '/negotiate', { method: 'POST' });\n  const json = await res.json();\n  return !('ProtocolVersion' in json);\n}\n// if (!await isAspNetCoreHub(url)) throw new Error('not a Core hub');","typeGuard":"function isCoreNegotiateResponse(r: any): boolean {\n  return r && !('ProtocolVersion' in r);\n}","tryCatchPattern":"try { await hub.start(); }\ncatch (e) {\n  if (/ASP.NET SignalR Server/.test(String(e))) {\n    throw new Error('Wrong client/server combo: server is legacy ASP.NET SignalR, use jquery.signalR or fix endpoint');\n  }\n  throw e;\n}","preventionTips":["Confirm the endpoint path is the Core MapHub route, not ~/signalr.","Match the client package (@microsoft/signalr) to a Core server.","Check negotiate JSON: Core does not return ProtocolVersion."],"tags":["version-mismatch","aspnet","server-compatibility","negotiate"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}