dotnet/aspnetcore · error · RuntimeException
Error reading length header.
Error message
Error reading length header.
What it means
Utils.readLengthHeader reads the length prefix and may throw IOException for malformed prefix bytes or insufficient data. MessagePackHubProtocol catches that IOException and wraps it as a RuntimeException with 'Error reading length header.' This is the entry-point parse failure: the framing could not even be read.
Solutions
- Confirm both server and client negotiate the same protocol - if the server only has JSON, do not call withHubProtocol(MessagePackHubProtocol).
- On the server register AddMessagePackProtocol() if you intend to use MessagePack; on the client ensure the negotiated protocol is MessagePack.
- Inspect the first few bytes of the failing frame to confirm they look like a MessagePack length header (varint).
Example fix
// before - client forces MessagePack but server has only JSON
HubConnectionBuilder.create(url)
.withHubProtocol(new MessagePackHubProtocol())
.build();
// after - register MessagePack on the server too
// server: services.AddSignalR().AddMessagePackProtocol();
HubConnectionBuilder.create(url)
.withHubProtocol(new MessagePackHubProtocol())
.build(); Defensive patterns
Strategy: validation
Validate before calling
// Confirm the negotiated protocol matches what you configured.
// After start(), inspect handshake result / server response to ensure
// 'messagepack' was accepted (not silently falling back to JSON).
// Pre-flight: hit /negotiate and check that the server lists messagepack.
Set<String> protocols = fetchNegotiate(url).availableTransports
.stream().flatMap(t -> t.getTransferFormats().stream())
.collect(toSet()); // adjust to your server's negotiate shape
if (!protocols.contains("messagepack")) {
throw new IllegalStateException("Server does not offer MessagePack");
} Try / catch
hub.onClosed(ex -> {
if (ex != null && ex.getMessage().contains("Error reading length header")) {
// protocol mismatch; verify AddMessagePackProtocol on server
}
}); Prevention
- Register AddMessagePackProtocol() on the server whenever the client uses MessagePackHubProtocol.
- Negotiate smoke-test that the server advertises the messagepack protocol.
- Do not mix a custom subprotocol that changes the wire format.
When it happens
Trigger: The first bytes of a MessagePack frame are not a valid length-header encoding, or the buffer has fewer than the header byte count; the protocol received binary data that is not MessagePack at all.
Common situations: Hub endpoint configured with JSON on the server but the client selected MessagePack (or vice-versa); a custom subprotocol mismatched the wire format; binary corruption from a transport layer; a stale buffer reused after a reconnect.
Related errors
- Error reading MessagePack data.
- Invalid invocation result kind.
- MessagePack message was length
- Unexpected message type
- A valid url is required.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/c7e0c53c072fbddd.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/java/signalr/messagepack/src/main/java/com/microsoft/signalr/messagepack/MessagePackHubProtocol.java:86
// MessagePack library can't handle read-only ByteBuffer - copy into an array-backed ByteBuffer if this is the case
if (payload.isReadOnly()) {
byte[] payloadBytes = new byte[payload.remaining()];
payload.get(payloadBytes, 0, payloadBytes.length);
payload = ByteBuffer.wrap(payloadBytes);
}
List<HubMessage> hubMessages = new ArrayList<>();
while (payload.hasRemaining()) {
int length;
try {
length = Utils.readLengthHeader(payload);
// Throw if remaining buffer is shorter than length header
if (payload.remaining() < length) {
throw new RuntimeException(String.format("MessagePack message was length %d but claimed to be length %d.", payload.remaining(), length));
}
} catch (IOException ex) {
throw new RuntimeException("Error reading length header.", ex);
}
// Instantiate MessageUnpacker
try(MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(payload)) {
int itemCount = unpacker.unpackArrayHeader();
HubMessageType messageType = HubMessageType.values()[unpacker.unpackInt() - 1];
switch (messageType) {
case INVOCATION:
hubMessages.add(createInvocationMessage(unpacker, binder, itemCount, payload));
break;
case STREAM_ITEM:
hubMessages.add(createStreamItemMessage(unpacker, binder, payload));
break;
case COMPLETION:
hubMessages.add(createCompletionMessage(unpacker, binder, payload));
break;
case STREAM_INVOCATION:View on GitHub (pinned to 3600ca084e)