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

  1. Only call writeMessage with one of the seven supported concrete message types; gate on hubMessage.getMessageType() before writing.
  2. Ensure the SignalR Java client build matches the server's protocol version so no unknown message kinds are produced.
  3. 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

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


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)