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
- Log the reader index where the failure occurs and hex-dump surrounding bytes to see whether the varint is truncated or misaligned.
- Verify the framing layer delivers complete messages (LengthFieldBasedFrameDecoder with correct lengthAdjustment).
- Ensure encoder and decoder share the same field order and varint encoding (same codec version both ends).
- 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
- Length-prefix every binary message so varints never straddle frames.
- Fuzz-test codecs with truncated buffers to confirm they fail closed.
- Pin encoder/decoder versions.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unsupported message type(%s).
- Unrecognized version(%s) for binary message codec!
- Malformed variable int %s!
- Error message type : %s
- Unrecognized version(%s) for binary metric bag!
AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14).
Data as JSON: /api/errors/d37305f6dc487b40.
Report an issue: GitHub.