{"record":{"id":"3c4250630f4baca8","repo":"dianping/cat","slug":"malformed-variable-int-s-3c4250","errorCode":null,"errorMessage":"Malformed variable int %s!","messagePattern":"Malformed variable int (.+?)!","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"cat-core/src/main/java/com/dianping/cat/message/codec/NativeMetricBagDecoder.java","lineNumber":109,"sourceCode":"\n\t\t\tm_buf.readBytes(data, 0, len);\n\t\t\treturn new String(data, 0, len, UTF_8);\n\t\t}\n\n\t\tprivate long readVarint(int length) {\n\t\t\tint shift = 0;\n\t\t\tlong result = 0;\n\n\t\t\twhile (shift < length) {\n\t\t\t\tfinal byte b = m_buf.readByte();\n\t\t\t\tresult |= (long) (b & 0x7F) << shift;\n\t\t\t\tif ((b & 0x80) == 0) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\tshift += 7;\n\t\t\t}\n\n\t\t\tthrow new RuntimeException(\"Malformed variable int \" + length + \"!\");\n\t\t}\n\n\t\tpublic String readVersion() {\n\t\t\tbyte[] bytes = new byte[3];\n\n\t\t\tm_buf.readBytes(bytes);\n\n\t\t\treturn new String(bytes);\n\t\t}\n\t}\n\n\tprivate static class MyMetric implements Metric {\n\t\tprivate long m_timestamp;\n\n\t\tprivate String m_name;\n\n\t\tprivate Kind m_kind;\n","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/dianping/cat/blob/e815e74d4c2dd74edac831241f1253fcc7d25381/cat-core/src/main/java/com/dianping/cat/message/codec/NativeMetricBagDecoder.java#L91-L127","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: raw TCP read loop\nbyte[] chunk = new byte[available]; in.read(chunk); decoder.decode(wrap(chunk)); // split -> throws\n\n// after: read length prefix then whole payload\nint len = in.readInt(); byte[] payload = new byte[len]; in.readFully(payload);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (RuntimeException e) { if (e.getMessage().startsWith(\"Malformed variable int\")) { discard partial metric bag; metrics self-heal next aggregation window; } else throw e; }","preventionTips":["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."],"tags":["protocol","metrics","varint","framing"],"backgroundTag":null,"analyzedSha":"e815e74d4c2dd74edac831241f1253fcc7d25381","analyzedAt":"2026-08-14T14:22:34.512Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}