dotnet/aspnetcore · error · RuntimeException

Extension types are not supported

Error message

Extension types are not supported

What it means

readValue switches on the msgpack ValueType of the next value; when it is EXTENSION the protocol deliberately throws because MessagePack extension types (custom application types, msgpack timestamps, etc.) have no deserializer wired up - the handling code is commented out at MessagePackHubProtocol.java:626-632.

Solutions

  1. On the server, format the offending value as a primitive/string/POJO instead of a MessagePack extension type.
  2. Convert timestamps to ISO-8601 strings or epoch longs before sending.
  3. Register a client-side equivalent formatter only if you fork the protocol to re-enable the commented-out ext path.

Example fix

// before (.NET) - formatter writes an ext type
options.FormatterResolvers = new[] { StandardResolverWithDateTime.KindDetection };
// after - send DateTime as an ISO string
hubContext.Clients.All.SendAsync("M", myDate.ToString("O"));
Defensive patterns

Strategy: type-guard

Validate before calling

// On the server side, ensure values are not encoded as MessagePack ext by converting
// e.g. DateTime -> ISO-8601 string before sending.
string payload = dateTime.ToString("O", CultureInfo.InvariantCulture);

Type guard

// The Java client cannot guard ext types on the wire; guard at the source by not producing them.
// Avoid registering formatters that emit ext format codes.

Try / catch

try {
    List<HubMessage> msgs = protocol.parseMessages(buffer, binder);
} catch (RuntimeException ex) {
    if ("Extension types are not supported".equals(ex.getMessage())) {
        // server is sending an ext-encoded value; fix server-side serialization
        log.error("Server sent an unsupported msgpack extension type", ex);
    }
    throw ex;
}

Prevention

When it happens

Trigger: A value on the wire is encoded as a MessagePack extension type (the high-level format with a type tag). This happens when the server serializes a type that its MessagePack formatter emits as an ext, e.g. DateTime/timestamp via a custom formatter, or a type using MessagePack-CSharp's ext-code paths.

Common situations: Server uses a custom IMessagePackFormatter that writes ext-format bytes; .NET DateTime serialized with a timestamp ext; interop with a non-standard MessagePack producer.

Related errors


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

Appendix: source

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

                    if (itemType == null) {
                        return null;
                    }
                    return objectMapper.readValue(payloadBytes, payload.position() + (int) readBytesStart, (int) (unpacker.getTotalReadBytes() - readBytesStart),
                            typeFactory.constructType(itemType));
                } else {
                    // This is an inner call to readValue - we just need to read the right number of bytes
                    // We can return null, and the outermost call will know how many bytes to give to objectMapper.
                    return null;
                }
            case EXTENSION:
                /*
                ExtensionTypeHeader extension = unpacker.unpackExtensionTypeHeader();
                byte[] extensionValue = new byte[extension.getLength()];
                unpacker.readPayload(extensionValue);
                //Convert this to an object?
                item = extensionValue;
                */
                throw new RuntimeException("Extension types are not supported");
            default:
                return null;
        }
        // If itemType was null, we were just in this method to advance the buffer. return null.
        if (itemType == null) {
            return null;
        }
        // If we get here, the item isn't a map or a collection/array, so we use the Class to cast it
        if (itemClass.isPrimitive()) {
            return Utils.toPrimitive(itemClass, item);
        }
        return itemClass.cast(item);
    }

    private void writeValue(Object o, MessagePacker packer) throws IOException {
        packer.addPayload(objectMapper.writeValueAsBytes(o));
    }
}

View on GitHub (pinned to 3600ca084e)