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

  1. Dump bytes at the failure index; confirm whether the field is truncated or the cursor is misplaced.
  2. Use length-prefixed framing sized to the largest metric bag so payloads never split mid-field.
  3. Match client/server versions so NM1 field order is identical on both ends.
  4. 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

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

Related errors


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