{"record":{"id":"2701e34f2b48609a","repo":"dotnet/runtime","slug":"err22","errorCode":"ERR22","errorMessage":"ERR22: WebSocket receive expected ArrayBuffer","messagePattern":"ERR22: WebSocket receive expected ArrayBuffer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/web-socket.ts","lineNumber":360,"sourceCode":"    return pcs.promise;\n}\n\nfunction webSocketOnMessage(ws: WebSocketExtension, event: MessageEvent) {\n    const eventQueue = ws[wasmWsPendingReceiveEventQueue];\n    const promiseQueue = ws[wasmWsPendingReceivePromiseQueue];\n\n    if (typeof event.data === \"string\") {\n        eventQueue.enqueue({\n            type: 0, // WebSocketMessageType.Text\n            // according to the spec https://encoding.spec.whatwg.org/\n            // - Unpaired surrogates will get replaced with 0xFFFD\n            // - utf8 encode specifically is defined to never throw\n            data: dotnetBrowserUtilsExports.stringToUTF8(event.data),\n            offset: 0\n        });\n    } else {\n        if (event.data.constructor.name !== \"ArrayBuffer\") {\n            throw new Error(\"ERR22: WebSocket receive expected ArrayBuffer\");\n        }\n        eventQueue.enqueue({\n            type: 1, // WebSocketMessageType.Binary\n            data: new Uint8Array(event.data),\n            offset: 0\n        });\n    }\n    if (promiseQueue.getLength() && eventQueue.getLength() > 1) {\n        throw new Error(\"ERR21: Invalid WS state\");// assert\n    }\n    while (promiseQueue.getLength() && eventQueue.getLength()) {\n        const promiseControl = promiseQueue.dequeue()!;\n        webSocketReceiveBuffering(ws, eventQueue, promiseControl.bufferPtr, promiseControl.bufferLength);\n        promiseControl.resolve();\n    }\n    preventTimerThrottling();\n}\n","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/web-socket.ts#L342-L378","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst ws = new WebSocket(url);\nws.binaryType = 'blob'; // breaks dotnet wasm receive loop\n\n// after\nconst ws = new WebSocket(url);\nws.binaryType = 'arraybuffer'; // required by dotnet wasm","handlingStrategy":"validation","validationCode":"function wsReceiveSafe(ws: WebSocket): boolean {\n  // The dotnet runtime sets this at creation; do not let user code change it.\n  return ws.binaryType === 'arraybuffer';\n}\n\n// Before using a socket the runtime will receive on:\nif (!wsReceiveSafe(myWs)) {\n  throw new Error('WebSocket.binaryType must be \"arraybuffer\" for dotnet wasm receive');\n}","typeGuard":"function isArrayBufferSocket(ws: WebSocket): boolean {\n  return ws.binaryType === 'arraybuffer';\n}","tryCatchPattern":"try {\n  await clientWebSocket.ReceiveAsync(buf, ct);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('ERR22')) {\n    // event.data was not ArrayBuffer; binaryType was changed or a non-compliant polyfill is in use.\n    throw new Error('WebSocket binaryType must be \"arraybuffer\"; check polyfill/user code.', { cause: e });\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["dotnet-wasm","websocket","network","typescript","binary"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}