dianping/cat · critical · RuntimeException

Unsupported message type(%s).

Error message

Unsupported message type(%s).

What it means

In NativeMessageCodec.decode, each child message begins with a one-char tag: 't' transaction, 'T' transaction end, 'E' event, 'M' metric, 'H' heartbeat, 'L' trace. The default branch throws RuntimeException("Unsupported message type(%s)." , ch) for any other character, meaning the byte stream is corrupt or misaligned — the decoder is reading where a type tag was expected.

Source

Thrown at cat-core/src/main/java/com/dianping/cat/message/codec/NativeMessageCodec.java:92

				Message e = Codec.EVENT.decode(ctx, buf);

				ctx.addChild(e);
				break;
			case 'M':
				Codec.METRIC.decode(ctx, buf);
				break;
			case 'H':
				Message h = Codec.HEARTBEAT.decode(ctx, buf);

				ctx.addChild(h);
				break;
			case 'L':
				Message l = Codec.TRACE.decode(ctx, buf);

				ctx.addChild(l);
				break;
			default:
				throw new RuntimeException(String.format("Unsupported message type(%s).", ch));
			}
		}

		if (msg == null) {
			msg = ctx.getMessageTree().getMessage();
		}

		return msg;
	}

	@Override
	public ByteBuf encode(MessageTree tree) {
		ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer(4 * 1024);

		try {
			Context ctx = new Context(tree);

			buf.writeInt(0); // place-holder

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Dump the buffer around the failure offset; verify the byte where decoding stopped is one of t/T/E/M/H/L.
  2. Confirm encoder and decoder run the same NativeMessageCodec version on both ends (upgrade together).
  3. Check the Netty pipeline framing (split frames, missing length-field prep) and the CAT server's max-message-size/child-message limits.
  4. Guard against double-decode of the same ByteBuf (retain/release and readerIndex bugs).

Example fix

// before: no size guard, oversized tree arrives truncated
serverSocketHandler.decode(buf); // mid-tree byte != tag -> throws

// after: enforce same limits both ends
int MAX = 8192; // align with server child-message cap
if (tree.getMessages().size() > MAX) tree.getMessages().subList(MAX, tree.getMessages().size()).clear();
Defensive patterns

Strategy: try-catch

Try / catch

catch (RuntimeException e) { if (e.getMessage().startsWith("Unsupported message type")) { log corrupt peer + offset; drop connection; } else throw e; }

Prevention

When it happens

Trigger: Decoding an NT1 buffer whose framing is broken: a truncated message, a payload truncated by TCP message-size limits, field-order mismatch between encoder/decoder versions, or a buffer accidentally double-decoded so the cursor sits on a data byte rather than a tag.

Common situations: Cat-client and cat-core protocol drift after partial upgrades; Netty frame decoders (DelimiterBased/LengthBased) misconfigured so messages split mid-record; payloads exceeding server-side max message size and being silently cut.

Related errors


AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14). Data as JSON: /api/errors/5d2c2baf87cf882c. Report an issue: GitHub.