dotnet/aspnetcore · error · Error

Message is incomplete.

Error message

Message is incomplete.

What it means

While parsing a binary handshake response, HandshakeProtocol looks for the RecordSeparator byte (0x1E) in the incoming Uint8Array. If indexOf returns -1, the buffer does not contain a complete handshake frame, so the message is incomplete and cannot be parsed.

Solutions

  1. Confirm the endpoint is an ASP.NET Core SignalR hub speaking the binary protocol.
  2. If you are buffering manually, ensure you accumulate bytes until the 0x1E separator arrives before calling parseHandshakeResponse.
  3. Retry the connection; transient fragmentation often resolves on reconnect.
  4. Inspect the raw incoming bytes (log message content) to verify the separator is missing vs. the data being garbage.
Defensive patterns

Strategy: retry

Validate before calling

function hasRecordSeparator(bytes: Uint8Array): boolean {
  return bytes.indexOf(0x1e) !== -1;
}
// accumulate until separator present before handing off to the protocol

Type guard

function isCompleteBinaryHandshake(bytes: Uint8Array): boolean {
  return bytes.indexOf(0x1e) !== -1;
}

Try / catch

import { HandshakeProtocol } from "@microsoft/signalr";
async function startWithRetry(conn: signalR.HubConnection, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try { await conn.start(); return; }
    catch (e) {
      if (e instanceof Error && e.message === "Message is incomplete." && i < attempts - 1) {
        await new Promise(r => setTimeout(r, 500 * (i + 1)));
        continue;
      }
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: parseHandshakeResponse receives an ArrayBuffer that lacks the 0x1E terminator. Happens when the transport delivered a partial frame (TCP fragmentation mid-handshake), when a binary protocol is fed a non-SignalR payload, or when the underlying transport's onreceive callback hands off an incomplete chunk.

Common situations: Slow or lossy network where the first chunk of the handshake arrives split. A proxy buffering or re-chunking the response. Mismatch between client transport expectation (binary) and what the server actually sent (text). Connecting to a non-SignalR binary endpoint.

Related errors


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

Appendix: source

Thrown at src/SignalR/clients/ts/signalr/src/HandshakeProtocol.ts:35

}

/** @private */
export class HandshakeProtocol {
    // Handshake request is always JSON
    public writeHandshakeRequest(handshakeRequest: HandshakeRequestMessage): string {
        return TextMessageFormat.write(JSON.stringify(handshakeRequest));
    }

    public parseHandshakeResponse(data: any): [any, HandshakeResponseMessage] {
        let messageData: string;
        let remainingData: any;

        if (isArrayBuffer(data)) {
            // Format is binary but still need to read JSON text from handshake response
            const binaryData = new Uint8Array(data);
            const separatorIndex = binaryData.indexOf(TextMessageFormat.RecordSeparatorCode);
            if (separatorIndex === -1) {
                throw new Error("Message is incomplete.");
            }

            // content before separator is handshake response
            // optional content after is additional messages
            const responseLength = separatorIndex + 1;
            messageData = String.fromCharCode.apply(null, Array.prototype.slice.call(binaryData.slice(0, responseLength)));
            remainingData = (binaryData.byteLength > responseLength) ? binaryData.slice(responseLength).buffer : null;
        } else {
            const textData: string = data;
            const separatorIndex = textData.indexOf(TextMessageFormat.RecordSeparator);
            if (separatorIndex === -1) {
                throw new Error("Message is incomplete.");
            }

            // content before separator is handshake response
            // optional content after is additional messages
            const responseLength = separatorIndex + 1;
            messageData = textData.substring(0, responseLength);

View on GitHub (pinned to 3600ca084e)