dotnet/aspnetcore · error · Error

Cannot read message size.

Error message

Cannot read message size.

What it means

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.

Solutions

  1. Confirm the SignalR server is sending complete frames (the server's MessageHubProtocol is the canonical source).
  2. Inspect the raw bytes at the failing offset — a length prefix whose continuation bits never terminate indicates truncation.
  3. If using a custom transport, ensure buffers accumulate until a complete frame is available before invoking parse.
  4. Treat this as a connection-level failure: close and re-establish the SignalR connection rather than retrying the parse.

Example fix

// before
const messages = BinaryMessageFormat.parse(partialBuffer);

// after — accumulate chunks until a full frame is available
function appendAndParse(acc, chunk) {
  const buf = concat(acc, chunk);
  try { return { consumed: ..., messages: BinaryMessageFormat.parse(buf) }; }
  catch (e) {
    if (/Cannot read message size/.test(e.message)) return { consumed: 0, messages: [], pending: buf };
    throw e;
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check: do we even have enough bytes for a length prefix?
function canReadLengthPrefix(buf: Uint8Array, offset: number, maxLen: number): boolean {
  for (let i = 0; i < maxLen; i++) {
    if (offset + i >= buf.byteLength) return false;
    if ((buf[offset + i] & 0x80) === 0) return true; // final byte of prefix
  }
  return true;
}

Type guard

function isCompleteLengthPrefix(buf: Uint8Array, offset: number, maxLen: number): boolean {
  for (let i = 0; offset + i < buf.byteLength && i < maxLen; i++) {
    if ((buf[offset + i] & 0x80) === 0) return true;
  }
  return false;
}

Try / catch

try {
  const messages = BinaryMessageFormat.parse(buffer);
} catch (e) {
  if (/Cannot read message size/.test((e as Error).message)) {
    // accumulate more bytes; the prefix was truncated
    pendingBuffer = concat(pendingBuffer, buffer);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/5195da7c59f67488. Report an issue: GitHub.

Appendix: source

Thrown at src/SignalR/clients/ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts:50

    public static parse(input: ArrayBuffer): Uint8Array[] {
        const result: Uint8Array[] = [];
        const uint8Array = new Uint8Array(input);
        const maxLengthPrefixSize = 5;
        const numBitsToShift = [0, 7, 14, 21, 28 ];

        for (let offset = 0; offset < input.byteLength;) {
            let numBytes = 0;
            let size = 0;
            let byteRead;
            do {
                byteRead = uint8Array[offset + numBytes];
                size = size | ((byteRead & 0x7f) << (numBitsToShift[numBytes]));
                numBytes++;
            }
            while (numBytes < Math.min(maxLengthPrefixSize, input.byteLength - offset) && (byteRead & 0x80) !== 0);

            if ((byteRead & 0x80) !== 0 && numBytes < maxLengthPrefixSize) {
                throw new Error("Cannot read message size.");
            }

            if (numBytes === maxLengthPrefixSize && byteRead > 7) {
                throw new Error("Messages bigger than 2GB are not supported.");
            }

            if (uint8Array.byteLength >= (offset + numBytes + size)) {
                // IE does not support .slice() so use subarray
                result.push(uint8Array.slice
                    ? uint8Array.slice(offset + numBytes, offset + numBytes + size)
                    : uint8Array.subarray(offset + numBytes, offset + numBytes + size));
            } else {
                throw new Error("Incomplete message.");
            }

            offset = offset + numBytes + size;
        }

View on GitHub (pinned to 3600ca084e)