dotnet/aspnetcore · error · RuntimeException

Error writing MessagePack data.

Error message

Error writing MessagePack data.

What it means

writeMessage wraps any MessagePackException or IOException raised while serializing a hub message's bytes into a RuntimeException with this message. It is a generic catch-all for an underlying serialization/packing failure of an InvocationMessage, StreamItem, Completion, etc. The original exception is attached as the cause, so the real reason (e.g. Jackson cannot serialize a type) is in ex.getCause().

Solutions

  1. Inspect ex.getCause() in the debugger/logs to find the underlying MessagePackException/IOException.
  2. Replace the offending argument type with one Jackson can serialize to MessagePack (POJO with default constructor, primitives, collections).
  3. Pin compatible versions of org.msgpack:msgpack-core and org.msgpack:msgpack-jackson-dataformat.

Example fix

// before
protocol.writeMessage(new InvocationMessage(headers, id, target, new Object[] { unsupportedType }));
// after - serialize a POJO Jackson can handle
public class MyArg { public String a; public int b; }
protocol.writeMessage(new InvocationMessage(headers, id, target, new Object[] { new MyArg() }));
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify arguments are Jackson-MessagePack-serializable before sending
ObjectMapper mp = new ObjectMapper(new MessagePackFactory());
for (Object arg : args) {
    try { mp.writeValueAsBytes(arg); }
    catch (Exception e) { throw new IllegalArgumentException("Unserializable argument " + arg, e); }
}

Type guard

// POJO with no-arg constructor and Jackson-friendly fields is the safe shape
static boolean isLikelySerializable(Object o) {
    return o == null || o instanceof Number || o instanceof CharSequence || o instanceof Boolean
        || o instanceof Collection || o instanceof Map
        || (o.getClass().getDeclaredConstructors().length > 0); // rough
}

Try / catch

try {
    protocol.writeMessage(message);
} catch (RuntimeException ex) {
    Throwable cause = ex.getCause();
    // log cause (MessagePackException / IOException) to find the offending field
    log.error("writeMessage failed: {}", cause, ex);
    throw ex;
}

Prevention

When it happens

Trigger: Any I/O or msgpack-core failure inside the try at MessagePackHubProtocol.java:147-188: a MessageBufferPacker write error, a Jackson ObjectMapper failure encoding an argument that has no MessagePack serializer, or a null field the packer cannot handle.

Common situations: Passing a non-serializable argument (e.g. a type with no default constructor / Jackson-incompatible), version drift in the msgpack/jackson-databind dependencies, or a corrupted ObjectMapper instance.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/e772f0442dafd4ee. Report an issue: GitHub.

Appendix: source

Thrown at src/SignalR/clients/java/signalr/messagepack/src/main/java/com/microsoft/signalr/messagepack/MessagePackHubProtocol.java:189

                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);
        }
    }

    private HubMessage createInvocationMessage(MessageUnpacker unpacker, InvocationBinder binder, int itemCount, ByteBuffer payload) throws IOException {
        Map<String, String> headers = readHeaders(unpacker);

        // invocationId may be nil
        String invocationId = null;
        if (!unpacker.tryUnpackNil()) {
            invocationId = unpacker.unpackString();
        }

        // For MsgPack, we represent an empty invocation ID as an empty string,
        // so we need to normalize that to "null", which is what indicates a non-blocking invocation.
        if (invocationId == null || invocationId.isEmpty()) {
            invocationId = null;
        }

View on GitHub (pinned to 3600ca084e)