dianping/cat · error · RuntimeException
Unsupported message(%s).
Error message
Unsupported message(%s).
What it means
NativeMessageCodec's encodeMessage throws RuntimeException("Unsupported message(%s).") — note it interpolates msg.toString(), not the class — when the object to encode is none of Transaction/Event/Metric/Heartbeat/Trace. This is the encode-side twin of the decode-side type-tag guard: the binary wire format simply has no tag for other Message implementations.
Source
Thrown at cat-core/src/main/java/com/dianping/cat/message/codec/NativeMessageCodec.java:154
Codec.TRANSACTION_START.encode(ctx, buf, msg);
for (Message child : children) {
if (child != null) {
encodeMessage(ctx, buf, child);
}
}
Codec.TRANSACTION_END.encode(ctx, buf, msg);
} else if (msg instanceof Event) {
Codec.EVENT.encode(ctx, buf, msg);
} else if (msg instanceof Metric) {
Codec.METRIC.encode(ctx, buf, msg);
} else if (msg instanceof Heartbeat) {
Codec.HEARTBEAT.encode(ctx, buf, msg);
} else if (msg instanceof Trace) {
Codec.TRACE.encode(ctx, buf, msg);
} else {
throw new RuntimeException(String.format("Unsupported message(%s).", msg));
}
}
enum Codec {
HEADER {
@Override
protected Message decode(Context ctx, ByteBuf buf) {
MessageTree tree = ctx.getMessageTree();
String version = ctx.getVersion(buf);
if (ID.equals(version)) {
tree.setDomain(ctx.readString(buf));
tree.setHostName(ctx.readString(buf));
tree.setIpAddress(ctx.readString(buf));
tree.setThreadGroupName(ctx.readString(buf));
tree.setThreadId(ctx.readString(buf));
tree.setThreadName(ctx.readString(buf));
tree.setMessageId(ctx.readString(buf));View on GitHub (pinned to e815e74d4c)
Solutions
- Read the object description in the exception message to identify which child is unsupported.
- Replace the custom implementation with DefaultEvent/DefaultTransaction/etc. so the standard tags apply.
- Sanitize the tree before send: drop or convert unknown message kinds.
- Upgrade CAT on both sides if a legitimate newer message type is involved.
Example fix
// before
Message raw = mock(Message.class); // not a known subtype
codec.encode(treeWith(raw)); // throws
// after
DefaultEvent ev = new DefaultEvent("Custom", "value");
codec.encode(treeWith(ev)); // 'E' tag Defensive patterns
Strategy: type-guard
Validate before calling
List<Message> keep = new ArrayList<>();
for (Message m : tree.getMessages())
if (m instanceof Transaction || m instanceof Event || m instanceof Metric || m instanceof Heartbeat || m instanceof Trace) keep.add(m);
tree.getMessages().retainAll(keep); Type guard
boolean encodable(Message m) { return m instanceof Transaction || m instanceof Event || m instanceof Metric || m instanceof Heartbeat || m instanceof Trace; } Prevention
- Ban bare Message implementations in code review; require Default* subclasses.
- Keep mocks out of real codec paths in tests.
When it happens
Trigger: Encoding a MessageTree whose children contain a bare Message implementation (mock, proxy, or plugin class) rather than one of the five built-in kinds; the toString() in the message identifies the offending object.
Common situations: Unit tests with mocked Message objects fed into the real codec; custom message classes from home-grown extensions; objects wrapped by dynamic proxies (AOP) that no longer instanceOf the known types.
Related errors
AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14).
Data as JSON: /api/errors/2043d562ef00a7be.
Report an issue: GitHub.