dotnet/runtime · error · Error

WebSockets are not supported in shell JS engine.

Error message

WebSockets are not supported in shell JS engine.

What it means

Thrown by verifyEnvironment (web-socket.ts) when ENVIRONMENT_IS_SHELL is true, i.e. the code is running inside a JS shell (V8 d8, SpiderMonkey jsshell) rather than a browser or Node. WebSocket networking is unavailable in those shells, so the runtime refuses to proceed before any socket operation.

Source

Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/web-socket.ts:495

    type: number, // WebSocketMessageType
    data: Uint8Array,
    offset: number
}

function resolvedPromise(): Promise<void> | null {
    // signal that we are finished synchronously
    // this is optimization, which doesn't allocate and doesn't require to marshal resolve() call to C# side.
    return null;
}

function rejectedPromise(message: string): Promise<any> | null {
    const resolved = Promise.reject(new Error(message));
    return wrapAsCancelable<void>(resolved);
}

function verifyEnvironment() {
    if (ENVIRONMENT_IS_SHELL) {
        throw new Error("WebSockets are not supported in shell JS engine.");
    }
    if (typeof globalThis.WebSocket !== "function") {
        const message = ENVIRONMENT_IS_NODE
            ? "Please install `ws` npm package to enable networking support."
            : "This browser doesn't support WebSocket API. Please use a modern browser. See also https://learn.microsoft.com/aspnet/core/blazor/supported-platforms";
        throw new Error(message);
    }
}

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Run the same code under Node (with the `ws` package) or a real browser instead of a JS shell.
  2. Guard the WebSocket code path behind an environment check and skip it in shell engines.
  3. Use a mock/in-process transport for shell-based tests instead of real WebSockets.

Example fix

// before (runs in d8/jsshell)
await clientWebSocket.ConnectAsync(uri, cts.Token);

// after
if (typeof globalThis.WebSocket === 'function') {
    await clientWebSocket.ConnectAsync(uri, cts.Token);
}
Defensive patterns

Strategy: fallback

Validate before calling

function canUseWebSocket(): boolean {
    // ENVIRONMENT_IS_SHELL equivalent
    const isShell = typeof (globalThis as any).process === "undefined" &&
                    typeof (globalThis as any).importScripts === "undefined" &&
                    typeof globalThis.WebSocket === "undefined";
    return !isShell;
}

Type guard

const supportsWebSocket = (): boolean =>
    typeof globalThis.WebSocket === "function" ||
    typeof (globalThis as any).require === "function";

Prevention

When it happens

Trigger: Running .NET WASM interop tests or scripts under d8/jsshell and invoking any WebSocket API (e.g. ClientWebSocket.ConnectAsync) on the C# side.

Common situations: Using the runtime's bundled shell harness for quick tests; CI scripts that default to a shell engine; reproducing a browser bug in d8.

Related errors


AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06). Data as JSON: /api/errors/7940420b033a5557. Report an issue: GitHub.