dotnet/aspnetcore · error · Error
Expected a handshake response from the server.
Error message
Expected a handshake response from the server.
What it means
After parsing the handshake frame, HandshakeProtocol checks whether the decoded JSON has a top-level 'type' field. A genuine handshake response has no type (it carries error/minorVersion/userId), so presence of type means the server sent a regular HubMessage instead of the expected handshake response — a protocol-level mismatch.
Solutions
- Match client and server SignalR versions (same major).
- If the server sends a handshake error, capture it server-side via its logs and resolve the underlying configuration.
- Retry the connection; a transient mid-stream condition can clear.
- Verify no proxy is reordering or re-framing the message stream.
Defensive patterns
Strategy: validation
Validate before calling
function isHandshakeResponse(obj: unknown): boolean {
return typeof obj === "object" && obj !== null && !("type" in obj);
} Type guard
function isHandshakeResponseMessage(v: unknown): v is { error?: string } {
return typeof v === "object" && v !== null && !("type" in v);
} Try / catch
try { await connection.start(); }
catch (e) {
if (e instanceof Error && e.message.includes("Expected a handshake response")) {
console.error("Protocol mismatch: client/server SignalR versions differ.");
}
throw e;
} Prevention
- Keep client and server SignalR majors aligned.
- Do not let a proxy reorder or re-frame the stream.
- Re-run the handshake on this error via withAutomaticReconnect().
When it happens
Trigger: parseHandshakeResponse decodes a JSON object that has a 'type' property. Happens when the server speaks an incompatible protocol version that puts an error in a typed message, when the client connected mid-stream and received a hub message first, or when the handshake response was malformed by a proxy.
Common situations: Client/server protocol version mismatch (e.g. an older server that emits a typed handshake error). Connecting to a hub that is mid-broadcast. A man-in-the-middle or debug proxy that re-frames messages.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Invalid headers.
- Invalid JS call result type
- Byte array index ' ' does not exist.
- Detected a connection attempt to an ASP.NET SignalR Server…
- Error reading JSON.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/468a038e6c1aa921.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/ts/signalr/src/HandshakeProtocol.ts:61
} 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);
remainingData = (textData.length > responseLength) ? textData.substring(responseLength) : null;
}
// At this point we should have just the single handshake message
const messages = TextMessageFormat.parse(messageData);
const response = JSON.parse(messages[0]);
if (response.type) {
throw new Error("Expected a handshake response from the server.");
}
const responseMessage: HandshakeResponseMessage = response;
// multiple messages could have arrived with handshake
// return additional data to be parsed as usual, or null if all parsed
return [remainingData, responseMessage];
}
}
View on GitHub (pinned to 3600ca084e)