dotnet/aspnetcore · error

Incomplete message.

Error message

Incomplete message.

What it means

Thrown by BinaryMessageFormat.parse after the length prefix is successfully read: the declared size plus the prefix length exceeds the available bytes in the input buffer. The frame header promises N payload bytes but fewer than N remain, so the message is incomplete.

Source

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

                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;
        }

        return result;
    }
}

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Ensure the transport only hands parse() fully-buffered frames (SignalR's WebSocket transport already does this).
  2. On transient partial frames, reconnect: with proper buffering this is not expected to persist.
  3. Inspect for proxy/intermediary truncation and raise frame-size limits.
  4. If building a custom host, accumulate bytes until at least one full frame (prefix+size) is available before parsing.

Example fix

// before (custom host)
BinaryMessageFormat.parse(partialBuffer); // partial -> throws

// after (custom host)
function tryParse(buf) {
  // accumulate until prefix-declared size is present
  const need = prefixSize + declaredSize;
  if (buf.byteLength < need) return null; // wait for more
  return BinaryMessageFormat.parse(buf);
}
Defensive patterns

Strategy: try-catch

Validate before calling

function tryParseFrame(buf) {
  // only parse when at least prefix+declared size are present
  const need = estimatePrefixSize(buf) + readDeclaredSize(buf);
  return buf.byteLength >= need ? BinaryMessageFormat.parse(buf) : null;
}

Type guard

null

Try / catch

try { BinaryMessageFormat.parse(buf); } catch (e) { if (/Incomplete message/i.test(e.message)) { /* buffer more bytes, retry */ } else throw e; }

Prevention

When it happens

Trigger: The parser received a buffer containing a complete prefix but only part of the payload — typical of streaming transports where a frame is split across reads. The SignalR transport is supposed to buffer whole frames before calling parse, so seeing this means the buffering layer delivered a partial frame or the declared size was wrong.

Common situations: Transport buffering regression; proxy truncation; size-prefix corruption declaring a too-large size; reconnect race delivering a buffer mid-frame; a custom host that calls parse on partial buffers.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/19eebd352650aeff. Report an issue: GitHub.