dianping/cat · critical · RuntimeException
Malformed variable int %s!
Error message
Malformed variable int %s!
What it means
NativeMetricBagDecoder's inner Context.readVarint implements the same LEB128 loop as the tree codec and throws RuntimeException("Malformed variable int <length>!") when no terminating byte (high bit clear) appears within the shift limit. It guards metric-bag fields like string lengths; hitting it means the NM1 payload is corrupt or out of sync with the reader.
Source
Thrown at cat-core/src/main/java/com/dianping/cat/message/codec/NativeMetricBagDecoder.java:109
m_buf.readBytes(data, 0, len);
return new String(data, 0, len, UTF_8);
}
private long readVarint(int length) {
int shift = 0;
long result = 0;
while (shift < length) {
final byte b = m_buf.readByte();
result |= (long) (b & 0x7F) << shift;
if ((b & 0x80) == 0) {
return result;
}
shift += 7;
}
throw new RuntimeException("Malformed variable int " + length + "!");
}
public String readVersion() {
byte[] bytes = new byte[3];
m_buf.readBytes(bytes);
return new String(bytes);
}
}
private static class MyMetric implements Metric {
private long m_timestamp;
private String m_name;
private Kind m_kind;
View on GitHub (pinned to e815e74d4c)
Solutions
- Dump bytes at the failure index; confirm whether the field is truncated or the cursor is misplaced.
- Use length-prefixed framing sized to the largest metric bag so payloads never split mid-field.
- Match client/server versions so NM1 field order is identical on both ends.
- Clamp/validate metric values (non-negative counts, durations within long range) before encoding to avoid pathological varints.
Example fix
// before: raw TCP read loop byte[] chunk = new byte[available]; in.read(chunk); decoder.decode(wrap(chunk)); // split -> throws // after: read length prefix then whole payload int len = in.readInt(); byte[] payload = new byte[len]; in.readFully(payload);
Defensive patterns
Strategy: try-catch
Try / catch
catch (RuntimeException e) { if (e.getMessage().startsWith("Malformed variable int")) { discard partial metric bag; metrics self-heal next aggregation window; } else throw e; } Prevention
- Send complete length-prefixed metric bags only.
- Validate counts/durations are sane before encoding.
- Metric data is periodic — prefer dropping one bad bag over crashing the collector.
When it happens
Trigger: Decoding an NM1 bag where a varint field never terminates: truncated payload (framing split mid-field), version drift altering field layout, or a value whose encoding exceeds the reader's width (e.g. a negative duration serialized as a huge unsigned varint).
Common situations: Metric aggregation payloads exceeding frame limits and being cut; rolling upgrades where client encoders write extra fields the server decoder does not expect, shifting the cursor into a varint mid-byte.
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
- Malformed variable int %s!
- Unrecognized version(%s) for binary metric bag!
- Unsupported MetricType Name!
- Error message type : %s
- Unsupported message type(%s).
AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14).
Data as JSON: /api/errors/3c4250630f4baca8.
Report an issue: GitHub.