dianping/cat · critical · RuntimeException

Malformed variable int %s!

Error message

Malformed variable int %s!

What it means

Context.readVarint in NativeMessageCodec decodes LEB128-style variable-length ints: each byte contributes 7 bits and must terminate with a high-bit-clear byte within 'length' shifts. If the loop exhausts the shift budget, the stream is malformed and RuntimeException("Malformed variable int <length>!") is thrown. Note the message interpolates the maximum shift count, not the actual bytes read.

Source

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

		public long readTimestamp(ByteBuf buf) {
			return readVarint(buf, 64);
		}

		protected long readVarint(ByteBuf buf, int length) {
			int shift = 0;
			long result = 0;

			while (shift < length) {
				final byte b = buf.readByte();
				result |= (long) (b & 0x7F) << shift;
				if ((b & 0x80) == 0) {
					return result;
				}
				shift += 7;
			}

			throw new RuntimeException("Malformed variable int " + length + "!");
		}

		public void writeDuration(ByteBuf buf, long duration) {
			writeVarint(buf, duration);
		}

		public void writeId(ByteBuf buf, char id) {
			buf.writeByte(id);
		}

		public void writeString(ByteBuf buf, String str) {
			if (str == null || str.length() == 0) {
				writeVarint(buf, 0);
			} else {
				byte[] data = str.getBytes(UTF8);

				writeVarint(buf, data.length);
				buf.writeBytes(data);

View on GitHub (pinned to e815e74d4c)

Solutions

  1. Log the reader index where the failure occurs and hex-dump surrounding bytes to see whether the varint is truncated or misaligned.
  2. Verify the framing layer delivers complete messages (LengthFieldBasedFrameDecoder with correct lengthAdjustment).
  3. Ensure encoder and decoder share the same field order and varint encoding (same codec version both ends).
  4. Check that durations/counts being encoded fit the varint width the reader supports (<= 9 bytes for 64-bit).

Example fix

// before: delimiter-based framing can split mid-message
new DelimiterBasedFrameDecoder(...); // varint cut at frame edge -> throws

// after: length-prefixed framing
new LengthFieldBasedFrameDecoder(1024*1024, 0, 4, 0, 4);
Defensive patterns

Strategy: try-catch

Try / catch

catch (RuntimeException e) { if (e.getMessage().startsWith("Malformed variable int")) { log readerIndex + hexdump window; drop connection; } else throw e; }

Prevention

When it happens

Trigger: Decoding an NT1 message where a varint field (durations, string lengths) is unterminated — every byte has bit 7 set past the allowed width. Caused by truncated payloads, buffer corruption, or desynchronized decoding (reading a varint where a different field type sits).

Common situations: TCP fragmentation cutting a message mid-varint when framing is wrong; server/client version drift changing field order so a string length is read as a varint body; extremely large durations encoded with a different varint width than the reader allows.

Understand the failure class

Related errors


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