dianping/cat · critical · RuntimeException

Unrecognized id(%s) for plain text message codec!

Error message

Unrecognized id(%s) for plain text message codec!

What it means

PlainTextMessageCodec.decodeHeader validates the message-id token read from a PT1 payload against the expected VERSION constant and throws RuntimeException("Unrecognized id(%s) for plain text message codec!") on mismatch. The plain-text protocol begins with a version/id line; a different token means the payload is not a PT1 message this codec can parse.

Source

Thrown at cat-core/src/main/java/com/dianping/cat/message/codec/PlainTextMessageCodec.java:131

		String threadName = helper.read(ctx, TAB);
		String messageId = helper.read(ctx, TAB);
		String parentMessageId = helper.read(ctx, TAB);
		String rootMessageId = helper.read(ctx, TAB);
		String sessionToken = helper.read(ctx, LF);

		if (VERSION.equals(id)) {
			tree.setDomain(domain);
			tree.setHostName(hostName);
			tree.setIpAddress(ipAddress);
			tree.setThreadGroupName(threadGroupName);
			tree.setThreadId(threadId);
			tree.setThreadName(threadName);
			tree.setMessageId(messageId);
			tree.setParentMessageId(parentMessageId);
			tree.setRootMessageId(rootMessageId);
			tree.setSessionToken(sessionToken);
		} else {
			throw new RuntimeException(String.format("Unrecognized id(%s) for plain text message codec!", id));
		}
	}

	protected Message decodeLine(Context ctx, DefaultTransaction parent, Stack<DefaultTransaction> stack,
	      MessageTree tree) {
		BufferHelper helper = m_bufferHelper;
		byte identifier = ctx.getBuffer().readByte();
		String timestamp = helper.read(ctx, TAB);
		String type = helper.read(ctx, TAB);
		String name = helper.read(ctx, TAB);

		switch (identifier) {
		case 't':
			DefaultTransaction transaction = new DefaultTransaction(type, name);

			tree.findOrCreateTransactions().add(transaction);

			helper.read(ctx, LF); // get rid of line feed

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Print the offending id from the exception; if it is 'NT1'/'NM1' the buffer was routed to the wrong codec.
  2. Route by the 3-byte tag before choosing plain-text vs native vs metric decoding (CodecHandler does this — bypassing it causes this error).
  3. Align client/server protocol versions.
  4. Check that the tab-delimited header line is intact (not truncated, no double encoding).

Example fix

// before
PlainTextMessageCodec codec = ...;
tree = codec.decode(buf); // buf actually starts 'NT1' -> throws

// after
MessageTree tree = new CodecHandler(plainCodec, nativeCodec, metricDecoder).decode(buf);
Defensive patterns

Strategy: validation

Validate before calling

String tag = buf.toString(buf.readerIndex(), 3, StandardCharsets.US_ASCII);
MessageTree t = "PT1".equals(tag) ? plainCodec.decode(buf) : codecHandler.decode(buf);

Try / catch

catch (RuntimeException e) { if (e.getMessage().contains("plain text message codec")) { re-route buffer to CodecHandler.decode; } else throw e; }

Prevention

When it happens

Trigger: Decoding a buffer whose header id token differs from VERSION — e.g. an NT1/NM1 binary payload reaching the plain-text codec, a corrupted header line, or a client with a different protocol revision.

Common situations: Wrong codec selected by a dispatcher; partial upgrades changing the id token; newline/tab framing issues that make the header token include stray bytes.

Related errors


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