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

verifyEnvironment throws this when ENVIRONMENT_IS_SHELL is true - i.e. the dotnet wasm runtime is running inside a JS shell interpreter (V8 d8, SpiderMonkey js, JavaScriptCore jsc, etc.) rather than a browser or Node. Those shells have no networking or WebSocket implementation, so the .NET ClientWebSocket implementation cannot operate.

Solutions

  1. Run the same workload under a browser or Node.js host instead of a JS shell.
  2. Skip or stub WebSocket-dependent tests when the host is a JS shell (gate on ENVIRONMENT_IS_SHELL in test setup).
  3. If you must use a shell, provide a WebSocket polyfill globalThis.WebSocket before the runtime initializes (uncommon; prefer Node).

Example fix

// before: tests run under d8 and invoke ClientWebSocket

// after: route WebSocket tests to Node runner
//   node --experimental-wasm-bigint test-runner.js  (provides globalThis.Webrtc/globalThis.WebSocket via ws)
Defensive patterns

Strategy: validation

Validate before calling

// Detect a JS shell host before booting dotnet, and skip WebSocket code paths.
function isJsShellHost(): boolean {
  // Heuristic: shells like d8/jsc lack a `window`/`self` and lack `WebSocket`.
  return typeof globalThis.WebSocket !== 'function'
    && typeof (globalThis as any).window === 'undefined'
    && typeof (globalThis as any).self === 'undefined'
    && typeof process === 'undefined';
}

if (isJsShellHost()) {
  console.warn('Skipping WebSocket tests: JS shell has no networking.');
}

Type guard

function supportsWebSocket(): boolean {
  return typeof globalThis.WebSocket === 'function';
}

Try / catch

try {
  await clientWebSocket.ConnectAsync(uri, ct);
} catch (e) {
  if (e instanceof Error && /shell JS engine/i.test(e.message)) {
    // Re-run under Node or a browser instead of a JS shell.
    throw new Error('WebSocket not available in JS shell host; switch to Node/browser.', { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling any ClientWebSocket API (ConnectAsync, or the runtime's wsCreate path) while the wasm runtime was booted inside d8/js/jsc. Reached at web-socket.ts:495 in verifyEnvironment(), which wsCreate calls before opening a socket.

Common situations: Running dotnet unit tests or smoke tests under d8/jsc and exercising a WebSocket code path. Using a JS shell as a lightweight host and forgetting it lacks networking. CI that picks the shell engine by default for speed.

Related errors


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

Appendix: 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 60108ba66e)