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
- Do not modify binaryType on the WebSocket created by the runtime; it must remain 'arraybuffer'.
- If using a Node `ws` polyfill, ensure it is configured to emit ArrayBuffer payloads (or wrap it so onmessage receives event.data as ArrayBuffer).
- Upgrade to a browser/polyfill that honors the binaryType='arraybuffer' contract.
- 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
- Never set ws.binaryType to anything other than 'arraybuffer'.
- Use a WebSocket polyfill that emits ArrayBuffer (the `ws` npm package does by default).
- Treat ERR22 as fatal for the socket; reconnect with a known-good configuration.
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
- WebSockets are not supported in shell JS engine.
- Please install `ws` npm package to enable networking support
- This browser doesn't support WebSocket API. Please use a mod
- Please install `ws` npm package to enable networking support
- NotImplementedException ${jsType}. ${jsinteropDoc}
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/2701e34f2b48609a.
Report an issue: GitHub.