dotnet/aspnetcore · error · Error
'WebSocket' is not supported in your environment.
Error message
'WebSocket' is not supported in your environment.
What it means
_constructTransport throws if WebSockets was selected but options.WebSocket is falsy. options.WebSocket is normally populated from the global WebSocket (browser) or the 'ws' npm module (Node); if neither resolved, the runtime has no WebSocket implementation to use.
Solutions
- Install 'ws' (npm install ws) when running on Node, or upgrade to Node 22+ where WebSocket is built-in.
- Provide a WebSocket implementation explicitly: withUrl(url, { WebSocket: MyWSImpl }).
- Fall back to a transport the environment supports (ServerSentEvents or LongPolling) by setting transport accordingly.
- Ensure your bundler does not tree-shake the global WebSocket polyfill.
Example fix
// before: Node without 'ws'
const conn = new signalR.HubConnectionBuilder()
.withUrl(url, { transport: signalR.HttpTransportType.WebSockets })
.build();
// after: supply an implementation
import WebSocket from "ws";
const conn = new signalR.HubConnectionBuilder()
.withUrl(url, { transport: signalR.HttpTransportType.WebSockets, WebSocket })
.build(); Defensive patterns
Strategy: validation
Validate before calling
function resolveWebSocket(): typeof WebSocket | undefined {
if (typeof WebSocket !== "undefined") return WebSocket;
try { return require("ws"); } catch { return undefined; }
}
const WS = resolveWebSocket();
if (!WS && process.versions?.node) await import("ws"); Type guard
function hasWebSocketImpl(opts: signalR.IHttpConnectionOptions): boolean {
return typeof opts.WebSocket === "function" || typeof WebSocket !== "undefined";
} Try / catch
try { await connection.start(); }
catch (e) {
if (e instanceof Error && /'WebSocket' is not supported/.test(e.message)) {
opts.WebSocket = require("ws");
return newConnection(opts);
}
throw e;
} Prevention
- Install 'ws' on Node, or run Node 22+ with built-in WebSocket.
- Pass WebSocket explicitly in options when bundling for non-browser targets.
- If the environment truly lacks WebSockets, fall back to LongPolling.
When it happens
Trigger: Transport selection picks HttpTransportType.WebSockets (explicitly or via auto-negotiate) but options.WebSocket was never set. The constructor only assigns WebSocket if global WebSocket exists or, under Platform.isNode, the 'ws' module loaded successfully.
Common situations: Running in Node without 'ws' installed (it's an optional peer dep). Running in an environment that lacks a global WebSocket (older browsers, some embedded engines). Bundler stripped the dynamic require('ws'). The user explicitly set transport: WebSockets in an environment that cannot support it.
Related errors
- 'EventSource' is not supported in your environment.
- Cannot resolve ' '.
- Negotiation can only be skipped when using the WebSocket…
- negotiateResponse.error
- Negotiation can only be skipped when using the WebSocket…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/5019d18464787640.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/ts/signalr/src/HttpConnection.ts:529
const message = "Failed to select transport before stop() was called.";
this._logger.log(LogLevel.Debug, message);
return Promise.reject(new AbortError(message));
}
}
}
}
if (transportExceptions.length > 0) {
return Promise.reject(new AggregateErrors(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`, transportExceptions));
}
return Promise.reject(new Error("None of the transports supported by the client are supported by the server."));
}
private _constructTransport(transport: HttpTransportType): ITransport {
switch (transport) {
case HttpTransportType.WebSockets:
if (!this._options.WebSocket) {
throw new Error("'WebSocket' is not supported in your environment.");
}
return new WebSocketTransport(this._httpClient, this._accessTokenFactory, this._logger, this._options.logMessageContent!,
this._options.WebSocket, this._options.headers || {});
case HttpTransportType.ServerSentEvents:
if (!this._options.EventSource) {
throw new Error("'EventSource' is not supported in your environment.");
}
return new ServerSentEventsTransport(this._httpClient, this._httpClient._accessToken, this._logger, this._options);
case HttpTransportType.LongPolling:
return new LongPollingTransport(this._httpClient, this._logger, this._options);
default:
throw new Error(`Unknown transport: ${transport}.`);
}
}
private _startTransport(url: string, transferFormat: TransferFormat): Promise<void> {
this.transport!.onreceive = this.onreceive;
if (this.features.reconnect) {View on GitHub (pinned to 3600ca084e)