dotnet/runtime · error · Error

ERR22

ERR22

Error message

ERR22: WebSocket receive expected ArrayBuffer

What it means

ERR22 is thrown by webSocketOnMessage when a binary WebSocket message arrives but event.data is not an ArrayBuffer instance (its constructor name differs). The .NET wasm WebSocket layer sets ws.binaryType='arraybuffer' at socket creation, so a non-ArrayBuffer binary frame means the contract was violated - either by an external party mutating binaryType, a polyfill that delivers Blob/Node Buffer, or a runtime that does not honor binaryType. The code aborts rather than mishandling the bytes.

Source

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

    return pcs.promise;
}

function webSocketOnMessage(ws: WebSocketExtension, event: MessageEvent) {
    const eventQueue = ws[wasmWsPendingReceiveEventQueue];
    const promiseQueue = ws[wasmWsPendingReceivePromiseQueue];

    if (typeof event.data === "string") {
        eventQueue.enqueue({
            type: 0, // WebSocketMessageType.Text
            // according to the spec https://encoding.spec.whatwg.org/
            // - Unpaired surrogates will get replaced with 0xFFFD
            // - utf8 encode specifically is defined to never throw
            data: dotnetBrowserUtilsExports.stringToUTF8(event.data),
            offset: 0
        });
    } else {
        if (event.data.constructor.name !== "ArrayBuffer") {
            throw new Error("ERR22: WebSocket receive expected ArrayBuffer");
        }
        eventQueue.enqueue({
            type: 1, // WebSocketMessageType.Binary
            data: new Uint8Array(event.data),
            offset: 0
        });
    }
    if (promiseQueue.getLength() && eventQueue.getLength() > 1) {
        throw new Error("ERR21: Invalid WS state");// assert
    }
    while (promiseQueue.getLength() && eventQueue.getLength()) {
        const promiseControl = promiseQueue.dequeue()!;
        webSocketReceiveBuffering(ws, eventQueue, promiseControl.bufferPtr, promiseControl.bufferLength);
        promiseControl.resolve();
    }
    preventTimerThrottling();
}

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Do not modify binaryType on the WebSocket created by the runtime; it must remain 'arraybuffer'.
  2. If using a Node `ws` polyfill, ensure it is configured to emit ArrayBuffer payloads (or wrap it so onmessage receives event.data as ArrayBuffer).
  3. Upgrade to a browser/polyfill that honors the binaryType='arraybuffer' contract.
  4. Catch the error in your C# WebSocket receive loop and surface a clearer message; treat it as a fatal transport error and reconnect.

Example fix

// before
const ws = new WebSocket(url);
ws.binaryType = 'blob'; // breaks dotnet wasm receive loop

// after
const ws = new WebSocket(url);
ws.binaryType = 'arraybuffer'; // required by dotnet wasm
Defensive patterns

Strategy: validation

Validate before calling

function wsReceiveSafe(ws: WebSocket): boolean {
  // The dotnet runtime sets this at creation; do not let user code change it.
  return ws.binaryType === 'arraybuffer';
}

// Before using a socket the runtime will receive on:
if (!wsReceiveSafe(myWs)) {
  throw new Error('WebSocket.binaryType must be "arraybuffer" for dotnet wasm receive');
}

Type guard

function isArrayBufferSocket(ws: WebSocket): boolean {
  return ws.binaryType === 'arraybuffer';
}

Try / catch

try {
  await clientWebSocket.ReceiveAsync(buf, ct);
} catch (e) {
  if (e instanceof Error && e.message.includes('ERR22')) {
    // event.data was not ArrayBuffer; binaryType was changed or a non-compliant polyfill is in use.
    throw new Error('WebSocket binaryType must be "arraybuffer"; check polyfill/user code.', { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: A C# ClientWebSocket receives a binary frame and the underlying JS WebSocket's binaryType was changed from 'arraybuffer' to 'blob' (or a Node `ws` polyfill that yields Buffer/Node Buffer objects instead of ArrayBuffer). Reached at web-socket.ts:360 when event.data.constructor.name !== 'ArrayBuffer' on a non-string message.

Common situations: Using a third-party WebSocket polyfill that defaults to Blob or Node Buffer. Code that sets ws.binaryType = 'blob' for inspection. An old browser engine that delivers message data as a different host object. A man-in-the-middle/proxy that re-wraps frames.

Related errors


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