{"record":{"id":"5195da7c59f67488","repo":"dotnet/aspnetcore","slug":"cannot-read-message-size","errorCode":null,"errorMessage":"Cannot read message size.","messagePattern":"Cannot read message size\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts","lineNumber":50,"sourceCode":"    public static parse(input: ArrayBuffer): Uint8Array[] {\n        const result: Uint8Array[] = [];\n        const uint8Array = new Uint8Array(input);\n        const maxLengthPrefixSize = 5;\n        const numBitsToShift = [0, 7, 14, 21, 28 ];\n\n        for (let offset = 0; offset < input.byteLength;) {\n            let numBytes = 0;\n            let size = 0;\n            let byteRead;\n            do {\n                byteRead = uint8Array[offset + numBytes];\n                size = size | ((byteRead & 0x7f) << (numBitsToShift[numBytes]));\n                numBytes++;\n            }\n            while (numBytes < Math.min(maxLengthPrefixSize, input.byteLength - offset) && (byteRead & 0x80) !== 0);\n\n            if ((byteRead & 0x80) !== 0 && numBytes < maxLengthPrefixSize) {\n                throw new Error(\"Cannot read message size.\");\n            }\n\n            if (numBytes === maxLengthPrefixSize && byteRead > 7) {\n                throw new Error(\"Messages bigger than 2GB are not supported.\");\n            }\n\n            if (uint8Array.byteLength >= (offset + numBytes + size)) {\n                // IE does not support .slice() so use subarray\n                result.push(uint8Array.slice\n                    ? uint8Array.slice(offset + numBytes, offset + numBytes + size)\n                    : uint8Array.subarray(offset + numBytes, offset + numBytes + size));\n            } else {\n                throw new Error(\"Incomplete message.\");\n            }\n\n            offset = offset + numBytes + size;\n        }\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts#L32-L68","documentation":"Thrown by BinaryMessageFormat.parse during SignalR MessagePack framing when the varint length prefix cannot be fully read. The parser reads up to maxLengthPrefixSize bytes of a 7-bit-prefixed length; if the high bit (0x80) is still set after exhausting the input buffer without reaching maxLengthPrefixSize, the prefix is truncated and unreadable.","triggerScenarios":"A MessagePack SignalR message arrives whose length-prefix bytes span the boundary of a partial read and the remaining bytes never arrive; a malformed/manually-crafted frame whose length prefix has all high bits set; a transport that delivered a slice mid-frame and the connection closed before more data arrived.","commonSituations":"Intermittent network drop mid-message over WebSockets; a proxy/CDN that fragments frames; corrupt wire data from a non-conforming server; feeding a hand-buffered (truncated) ArrayBuffer into the parser during testing.","solutions":["Confirm the SignalR server is sending complete frames (the server's MessageHubProtocol is the canonical source).","Inspect the raw bytes at the failing offset — a length prefix whose continuation bits never terminate indicates truncation.","If using a custom transport, ensure buffers accumulate until a complete frame is available before invoking parse.","Treat this as a connection-level failure: close and re-establish the SignalR connection rather than retrying the parse."],"exampleFix":"// before\nconst messages = BinaryMessageFormat.parse(partialBuffer);\n\n// after — accumulate chunks until a full frame is available\nfunction appendAndParse(acc, chunk) {\n  const buf = concat(acc, chunk);\n  try { return { consumed: ..., messages: BinaryMessageFormat.parse(buf) }; }\n  catch (e) {\n    if (/Cannot read message size/.test(e.message)) return { consumed: 0, messages: [], pending: buf };\n    throw e;\n  }\n}","handlingStrategy":"retry","validationCode":"// Pre-check: do we even have enough bytes for a length prefix?\nfunction canReadLengthPrefix(buf: Uint8Array, offset: number, maxLen: number): boolean {\n  for (let i = 0; i < maxLen; i++) {\n    if (offset + i >= buf.byteLength) return false;\n    if ((buf[offset + i] & 0x80) === 0) return true; // final byte of prefix\n  }\n  return true;\n}","typeGuard":"function isCompleteLengthPrefix(buf: Uint8Array, offset: number, maxLen: number): boolean {\n  for (let i = 0; offset + i < buf.byteLength && i < maxLen; i++) {\n    if ((buf[offset + i] & 0x80) === 0) return true;\n  }\n  return false;\n}","tryCatchPattern":"try {\n  const messages = BinaryMessageFormat.parse(buffer);\n} catch (e) {\n  if (/Cannot read message size/.test((e as Error).message)) {\n    // accumulate more bytes; the prefix was truncated\n    pendingBuffer = concat(pendingBuffer, buffer);\n    return;\n  }\n  throw e;\n}","preventionTips":["Buffer incoming bytes until a complete length prefix is present before parsing.","Use the official transport layer (which reassembles frames) instead of parsing raw chunks.","Treat unparseable frames as a connection-level failure."],"tags":["signalr","messagepack","framing","binary-protocol","corruption"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}