{"record":{"id":"856d2a7df26e31e5","repo":"dotnet/aspnetcore","slug":"negotiateresponse-error","errorCode":null,"errorMessage":"negotiateResponse.error","messagePattern":"negotiateResponse\\.error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/HttpConnection.ts","lineNumber":276,"sourceCode":"                    // We should just call connect directly in this case.\n                    // No fallback or negotiate in this case.\n                    await this._startTransport(url, transferFormat);\n                } else {\n                    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                }","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/ts/signalr/src/HttpConnection.ts#L258-L294","documentation":"If the /negotiate response body contains an 'error' field, the server is reporting a negotiation failure (e.g. hub not found, protocol unsupported, transport disabled). The client surfaces that server-provided string by throwing new Error(negotiateResponse.error).","triggerScenarios":"Any 200 negotiate response whose JSON contains an error string. The server's NegotiateMiddleware or hub endpoint wrote an error: \"...\" into the response. Causes include unknown hub, disallowed transport, invalid protocol, or a custom IConnection that rejects negotiation.","commonSituations":"Hub route typo (negotiate returns error indicating no hub). Server config disables all transports the client requested. Azure SignalR Service misconfigured (wrong endpoint/key yields an error in negotiate). ConnectionId could not be generated.","solutions":["Read the actual error string — it is the server's explanation (e.g. 'The Server was unable to negotiate...').","Verify the hub is registered at the exact route (case-sensitive) the client is hitting.","Confirm at least one transport the client allows is enabled on the server (ConfigureKestrel/AddSignalR options).","For Azure SignalR, check the connection string and that the endpoint is reachable."],"exampleFix":"// before\ntry { await connection.start(); }\ncatch (e) { console.error(e); }\n\n// after — surface the server error verbosely\ntry { await connection.start(); }\ncatch (e) {\n  if (typeof e.message === \"string\" && e.message.length)\n    console.error(\"Negotiate error from server:\", e.message);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight: hit negotiate and surface the server's error\nasync function probeNegotiate(url: string) {\n  const r = await fetch(`${url}/negotiate?negotiateVersion=1`, { method: \"POST\" });\n  const body = await r.json();\n  if (body.error) throw new Error(`Server negotiate error: ${body.error}`);\n  return body;\n}","typeGuard":"function hasNegotiateError(v: unknown): v is { error: string } {\n  return typeof v === \"object\" && v !== null && typeof (v as any).error === \"string\";\n}","tryCatchPattern":"try { await connection.start(); }\ncatch (e) {\n  const msg = (e instanceof Error && e.message) || \"\";\n  // The message IS the server-provided error string; log it for diagnosis\n  console.error(\"Server returned negotiate error:\", msg);\n  throw e;\n}","preventionTips":["Run a /negotiate probe in CI to catch hub-route/transport misconfig early.","Always log the raw error message — it is the server's explanation.","Confirm at least one client-allowed transport is enabled server-side."],"tags":["negotiation","server-error","transport","configuration"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}