{"record":{"id":"3c9f9d09cbb0ffec","repo":"dotnet/aspnetcore","slug":"errormessage-response-statustext","errorCode":null,"errorMessage":"errorMessage || response.statusText","messagePattern":"errorMessage \\|\\| response\\.statusText","errorType":"http","errorClass":"HttpError","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/FetchHttpClient.ts","lineNumber":143,"sourceCode":"                throw error;\n            }\n            this._logger.log(\n                LogLevel.Warning,\n                `Error from HTTP request. ${e}.`,\n            );\n            throw e;\n        } finally {\n            if (timeoutId) {\n                clearTimeout(timeoutId);\n            }\n            if (request.abortSignal) {\n                request.abortSignal.onabort = null;\n            }\n        }\n\n        if (!response.ok) {\n            const errorMessage = await deserializeContent(response, \"text\") as string;\n            throw new HttpError(errorMessage || response.statusText, response.status);\n        }\n\n        const content = deserializeContent(response, request.responseType);\n        const payload = await content;\n\n        return new HttpResponse(\n            response.status,\n            response.statusText,\n            payload,\n        );\n    }\n\n    public getCookieString(url: string): string {\n        let cookies: string = \"\";\n        if (Platform.isNode && this._jar) {\n            // @ts-ignore: unused variable\n            this._jar.getCookies(url, (e, c) => cookies = c.join(\"; \"));\n        }","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/ts/signalr/src/FetchHttpClient.ts#L125-L161","documentation":"When an HTTP response has response.ok === false, FetchHttpClient deserializes the response body as text and throws an HttpError whose message is that text, or the HTTP statusText if the body was empty. The HttpError carries the numeric statusCode so callers can branch on 401, 404, 500, etc.","triggerScenarios":"Any non-2xx response from a SignalR endpoint: negotiate returns 401 Unauthorized, the hub route returns 404, a long-poll request gets 500, or a CDN/proxy returns a 502 body. Surfaced through HttpConnection.start -> negotiate/transport requests.","commonSituations":"Hub endpoint not mapped on the server (404). Authentication failure or expired token (401/403). CORS preflight rejected (no ok response). Server-side exception during the request (500). Reverse proxy returning an HTML error page that becomes the error message.","solutions":["Catch HttpError specifically and inspect error.statusCode to differentiate 401 (re-auth) from 404 (wrong URL) from 5xx (server fault).","Confirm the SignalR hub is mapped at the URL you are hitting (e.g. app.MapHub<MyHub>(\"/hub\")).","Verify authentication: ensure access tokens are supplied and that CORS allows credentials if withCredentials is true.","If the message is HTML, a proxy/firewall is intercepting; whitelist the hub route."],"exampleFix":"// before\ntry {\n  await connection.start();\n} catch (e) {\n  console.error(e.message);\n}\n\n// after\nimport { HttpError } from \"@microsoft/signalr\";\ntry {\n  await connection.start();\n} catch (e) {\n  if (e instanceof HttpError) {\n    if (e.statusCode === 401) await refreshToken();\n    else if (e.statusCode === 404) throw new Error(\"Hub not found at \" + url);\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"function isOk(status: number): boolean { return status >= 200 && status < 300; }\n// before calling connection.start, verify reachability\nconst probe = await fetch(url + \"/negotiate?negotiateVersion=1\", { method: \"POST\" });\nif (!isOk(probe.status)) console.warn(\"Hub non-OK:\", probe.status);","typeGuard":"function isHttpError(e: unknown): e is signalR.HttpError {\n  return e instanceof Error && typeof (e as any).statusCode === \"number\";\n}","tryCatchPattern":"import { HttpError } from \"@microsoft/signalr\";\ntry { await connection.start(); }\ncatch (e) {\n  if (e instanceof HttpError) {\n    switch (e.statusCode) {\n      case 401: await refreshAccessToken(); break;\n      case 404: throw new Error(`Hub not found at ${url}`);\n      default: throw e;\n    }\n  } else throw e;\n}","preventionTips":["Always branch on HttpError.statusCode rather than parsing the message.","Probe /negotiate during health checks to catch 401/404 before runtime.","Ensure CORS allows the hub route and that auth tokens are fresh."],"tags":["http","http-error","authentication","cors","network"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}