{"record":{"id":"4594a02506260070","repo":"dotnet/aspnetcore","slug":"message-is-incomplete","errorCode":null,"errorMessage":"Message is incomplete.","messagePattern":"Message is incomplete\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/HandshakeProtocol.ts","lineNumber":35,"sourceCode":"}\n\n/** @private */\nexport class HandshakeProtocol {\n    // Handshake request is always JSON\n    public writeHandshakeRequest(handshakeRequest: HandshakeRequestMessage): string {\n        return TextMessageFormat.write(JSON.stringify(handshakeRequest));\n    }\n\n    public parseHandshakeResponse(data: any): [any, HandshakeResponseMessage] {\n        let messageData: string;\n        let remainingData: any;\n\n        if (isArrayBuffer(data)) {\n            // Format is binary but still need to read JSON text from handshake response\n            const binaryData = new Uint8Array(data);\n            const separatorIndex = binaryData.indexOf(TextMessageFormat.RecordSeparatorCode);\n            if (separatorIndex === -1) {\n                throw new Error(\"Message is incomplete.\");\n            }\n\n            // content before separator is handshake response\n            // optional content after is additional messages\n            const responseLength = separatorIndex + 1;\n            messageData = String.fromCharCode.apply(null, Array.prototype.slice.call(binaryData.slice(0, responseLength)));\n            remainingData = (binaryData.byteLength > responseLength) ? binaryData.slice(responseLength).buffer : null;\n        } else {\n            const textData: string = data;\n            const separatorIndex = textData.indexOf(TextMessageFormat.RecordSeparator);\n            if (separatorIndex === -1) {\n                throw new Error(\"Message is incomplete.\");\n            }\n\n            // content before separator is handshake response\n            // optional content after is additional messages\n            const responseLength = separatorIndex + 1;\n            messageData = textData.substring(0, responseLength);","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/ts/signalr/src/HandshakeProtocol.ts#L17-L53","documentation":"Thrown by HandshakeProtocol.parseHandshakeResponse in the binary branch when the ArrayBuffer does not contain a RecordSeparator (0x1e) byte. The handshake response is JSON text terminated by a record separator, and for binary protocols it arrives as the first chunk of an ArrayBuffer. Absence of the separator means the handshake response hasn't fully arrived or is malformed.","triggerScenarios":"The binary handshake chunk delivered to parseHandshakeResponse is incomplete (separator not yet received); a chunk that is actually a later message, not the handshake; the server never sent a proper handshake response.","commonSituations":"A transport delivered a partial first frame (the separator is in the next chunk); network latency splitting the handshake; a non-SignalR endpoint answering the WebSocket; server-side error closing the connection before sending the handshake response.","solutions":["Buffer incoming bytes until a 0x1e separator is present before calling parseHandshakeResponse.","Confirm the server URL points to a real SignalR hub endpoint.","Check server logs — if it crashed or rejected the protocol it may never send a valid handshake response.","Verify the negotiated protocol name is spelled correctly on the client."],"exampleFix":"// before\nconst [remaining, resp] = handshakeProtocol.parseHandshakeResponse(incompleteBuffer);\n\n// after\n// accumulate until the record separator byte (0x1e) is present\nif (new Uint8Array(buffer).indexOf(0x1e) === -1) {\n  // wait for more data\n  return;\n}\nconst [remaining, resp] = handshakeProtocol.parseHandshakeResponse(buffer);","handlingStrategy":"validation","validationCode":"// buffer until the record separator (0x1e) is present (binary path)\nconst SEP = 0x1e;\nfunction handshakeBufferComplete(buffer: ArrayBuffer): boolean {\n  return new Uint8Array(buffer).indexOf(SEP) !== -1;\n}\nif (!handshakeBufferComplete(buffer)) {\n  // wait for more data\n  return;\n}\nconst [remaining, resp] = handshakeProtocol.parseHandshakeResponse(buffer);","typeGuard":null,"tryCatchPattern":"try {\n  const [remaining, resp] = handshakeProtocol.parseHandshakeResponse(buffer);\n} catch (e) {\n  if (e.message === 'Message is incomplete.') {\n    // accumulate more bytes and retry once the separator arrives\n    return;\n  }\n  throw e;\n}","preventionTips":["Buffer binary chunks until a 0x1e byte appears before parsing the handshake.","Verify the endpoint is a real SignalR hub returning a proper binary handshake response.","Log the first chunk's byte length and hex to spot truncation."],"tags":["handshake","binary-protocol","parsing","network","messagepack"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}