dotnet/aspnetcore · error · RuntimeException
Unexpected message type
Error message
Unexpected message type: %d
What it means
Thrown by MessagePackHubProtocol.writeMessage when serializing a HubMessage whose getMessageType() value does not match any case in the write switch (INVOCATION, STREAM_ITEM, COMPLETION, STREAM_INVOCATION, CANCEL_INVOCATION, PING, CLOSE). The Java MessagePack protocol only knows how to write the seven defined SignalR message kinds; anything else is a programming error or a protocol/client-version mismatch, not a recoverable wire condition.
Solutions
- Only call writeMessage with one of the seven supported concrete message types; gate on hubMessage.getMessageType() before writing.
- Ensure the SignalR Java client build matches the server's protocol version so no unknown message kinds are produced.
- If you subclassed HubMessage, map it to a supported type instead of introducing a new getMessageType() value.
Example fix
// before
ByteBuffer out = protocol.writeMessage(customMessage); // customMessage.getMessageType() is unsupported
// after - only emit supported kinds
if (EnumSet.of(INVOCATION, STREAM_ITEM, COMPLETION, STREAM_INVOCATION, CANCEL_INVOCATION, PING, CLOSE).contains(message.getMessageType())) {
ByteBuffer out = protocol.writeMessage(message);
} else {
throw new IllegalArgumentException("Unsupported message type: " + message.getMessageType());
} Defensive patterns
Strategy: type-guard
Validate before calling
java.util.Set<HubMessageType> WRITABLE = java.util.EnumSet.of(
HubMessageType.INVOCATION, HubMessageType.STREAM_ITEM, HubMessageType.COMPLETION,
HubMessageType.STREAM_INVOCATION, HubMessageType.CANCEL_INVOCATION,
HubMessageType.PING, HubMessageType.CLOSE);
if (!WRITABLE.contains(message.getMessageType())) {
throw new IllegalArgumentException("Cannot write message type " + message.getMessageType());
} Type guard
// Only write messages the protocol can serialize
static boolean isWriteable(HubMessage m) {
return m != null && java.util.EnumSet.of(
HubMessageType.INVOCATION, HubMessageType.STREAM_ITEM, HubMessageType.COMPLETION,
HubMessageType.STREAM_INVOCATION, HubMessageType.CANCEL_INVOCATION,
HubMessageType.PING, HubMessageType.CLOSE).contains(m.getMessageType());
} Try / catch
try {
ByteBuffer out = protocol.writeMessage(message);
} catch (RuntimeException ex) {
if (ex.getMessage() != null && ex.getMessage().startsWith("Unexpected message type")) {
// unsupported message kind - do not retry, fix the caller
throw new IllegalArgumentException(ex);
}
throw ex;
} Prevention
- Never pass a custom HubMessage with an unrecognised getMessageType() into writeMessage.
- Keep the client and server on the same SignalR protocol version.
- Whitelist message types before invoking writeMessage.
When it happens
Trigger: Calling protocol.writeMessage(...) with a custom HubMessage subclass whose getMessageType() returns a value outside the seven known HubMessageType enum members, or using a message type added in a newer server protocol that this older client build does not recognize. The switch falls through to the default branch at MessagePackHubProtocol.java:172.
Common situations: Client and server running incompatible SignalR protocol versions, a hand-built HubMessage passed into writeMessage, or an enum value corruption where messageType.value is not in the supported set.
Related errors
- Error reading MessagePack data.
- Error reading length header.
- Error writing MessagePack data.
- Invalid invocation result kind.
- MessagePack message was length
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/a1700f576ae85432.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/java/signalr/messagepack/src/main/java/com/microsoft/signalr/messagepack/MessagePackHubProtocol.java:172
message = writeStreamItemMessage((StreamItem) hubMessage);
break;
case COMPLETION:
message = writeCompletionMessage((CompletionMessage) hubMessage);
break;
case STREAM_INVOCATION:
message = writeStreamInvocationMessage((StreamInvocationMessage) hubMessage);
break;
case CANCEL_INVOCATION:
message = writeCancelInvocationMessage((CancelInvocationMessage) hubMessage);
break;
case PING:
message = writePingMessage((PingMessage) hubMessage);
break;
case CLOSE:
message = writeCloseMessage((CloseMessage) hubMessage);
break;
default:
throw new RuntimeException(String.format("Unexpected message type: %d", messageType.value));
}
int length = message.length;
List<Byte> header = Utils.getLengthHeader(length);
byte[] messageWithHeader = new byte[header.size() + length];
int headerSize = header.size();
// Write the length header, then all of the bytes of the original message
for (int i = 0; i < headerSize; i++) {
messageWithHeader[i] = header.get(i);
}
for (int i = 0; i < length; i++) {
messageWithHeader[i + headerSize] = message[i];
}
return ByteBuffer.wrap(messageWithHeader);
} catch (MessagePackException | IOException ex) {
throw new RuntimeException("Error writing MessagePack data.", ex);
}View on GitHub (pinned to 3600ca084e)