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

  1. Read the object description in the exception message to identify which child is unsupported.
  2. Replace the custom implementation with DefaultEvent/DefaultTransaction/etc. so the standard tags apply.
  3. Sanitize the tree before send: drop or convert unknown message kinds.
  4. 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

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.