OrchardCMS/OrchardCore · critical · Error
No usable HttpClient found.
Error message
No usable HttpClient found.
What it means
HttpConnection's constructor throws 'No usable HttpClient found.' when neither the WHATWG fetch API (fetch/AbortController) nor XMLHttpRequest is available in the runtime. The SignalR client needs at least one of these to perform HTTP requests, and it fails at connection construction rather than at first send.
Solutions
- Install a fetch polyfill (e.g. whatwg-fetch, node-fetch assigned to globalThis) before importing/using the client
- In Node, import '@microsoft/signalr' (the Node build) instead of the browser 'signalr.js' bundle
- Ensure the test/SSR environment provides fetch or XMLHttpRequest globals
- Target a browser that supports fetch (or supply XHR fallback)
Example fix
// before (Node, browser bundle)
import { HubConnectionBuilder } from './wwwroot/Scripts/signalr.js';
// after
import * as signalr from '@microsoft/signalr'; // Node-compatible entry
if (!globalThis.fetch) globalThis.fetch = (await import('node-fetch')).default; Defensive patterns
Strategy: fallback
Validate before calling
if (typeof fetch === 'undefined' && typeof XMLHttpRequest === 'undefined') throw new Error('SignalR requires fetch or XMLHttpRequest polyfill'); Type guard
const hasHttpStack = () => typeof globalThis.fetch !== 'undefined' || typeof globalThis.XMLHttpRequest !== 'undefined';
Try / catch
try { connection = new HubConnectionBuilder().withUrl(url).build(); } catch (e) { if (e.message === 'No usable HttpClient found.') installPolyfill(); } Prevention
- Import the Node entry (@microsoft/signalr) outside browsers
- Polyfill fetch for SSR/tests/workers before importing the client
- Lint against importing the browser bundle in server code
When it happens
Trigger: Running the browser build of signalr.js in Node.js without a fetch polyfill; very old browsers lacking both fetch and XHR; restricted environments (web workers/SSR) where globals are stripped.
Common situations: Server-side rendering importing the browser bundle; Jest/jsdom tests with outdated environment flags; embedding the client in a sandboxed worker without network globals.
Understand the failure class
Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.
Related errors
- jQuery requires a window with a document
- could not find global
- 'WebSocket' is not supported in your environment.
- jQuery requires a window with a document
- jQuery requires a window with a document
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/c4d40635912959e1.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.SignalR/wwwroot/Scripts/signalr.js:816
// The .NET Foundation licenses this file to you under the MIT license.
/** Default implementation of {@link @microsoft/signalr.HttpClient}. */
class DefaultHttpClient extends HttpClient {
/** Creates a new instance of the {@link @microsoft/signalr.DefaultHttpClient}, using the provided {@link @microsoft/signalr.ILogger} to log messages. */
constructor(logger) {
super();
if (typeof fetch !== "undefined" || Platform.isNode) {
this._httpClient = new FetchHttpClient(logger);
}
else if (typeof XMLHttpRequest !== "undefined") {
this._httpClient = new XhrHttpClient(logger);
}
else {
throw new Error("No usable HttpClient found.");
}
}
/** @inheritDoc */
send(request) {
// Check that abort was not signaled before calling send
if (request.abortSignal && request.abortSignal.aborted) {
return Promise.reject(new AbortError());
}
if (!request.method) {
return Promise.reject(new Error("No method defined."));
}
if (!request.url) {
return Promise.reject(new Error("No url defined."));
}
return this._httpClient.send(request);
}
getCookieString(url) {
return this._httpClient.getCookieString(url);View on GitHub (pinned to 4306c0717f)