{"record":{"id":"e7e8791b579dd92b","repo":"openzipkin/zipkin","slug":"greater-than-64-bit-varint-at-position","errorCode":null,"errorMessage":"Greater than 64-bit varint at position {}","messagePattern":"Greater than 64-bit varint at position (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/internal/ReadBuffer.java","lineNumber":366,"sourceCode":"\n    b = readByte();\n    if ((b & 0xf0) != 0) {\n      throw new IllegalArgumentException(\"Greater than 32-bit varint at position \" + (pos() - 1));\n    }\n    return result | b << 28;\n  }\n\n  final long readVarint64() {\n    byte b; // negative number implies MSB set\n    if ((b = readByte()) >= 0) {\n      return b;\n    }\n\n    long result = b & 0x7f;\n    for (int i = 1; b < 0 && i < 10; i++) {\n      b = readByte();\n      if (i == 9 && (b & 0xf0) != 0) {\n        throw new IllegalArgumentException(\"Greater than 64-bit varint at position \" + (pos() - 1));\n      }\n      result |= (long) (b & 0x7f) << (i * 7);\n    }\n    return result;\n  }\n\n  final void require(int byteCount) {\n    if (this.available() < byteCount) {\n      throw new IllegalArgumentException(\n        \"Truncated: length \" + byteCount + \" > bytes available \" + this.available());\n    }\n  }\n\n  int checkReadArguments(byte[] dst, int offset, int length) {\n    if (dst == null) throw new NullPointerException();\n    if (offset < 0 || length < 0 || length > dst.length - offset) {\n      throw new IndexOutOfBoundsException();\n    }","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/internal/ReadBuffer.java#L348-L384","documentation":"ReadBuffer.readVarint64 accepts at most 10 bytes; on the 10th byte any value bits above the low 4 ((b & 0xf0) != 0) mean the number exceeds 64 bits, and it throws 'Greater than 64-bit varint at position P'. Real protobuf never produces this; it indicates corrupt bytes or a stream that lost field alignment.","triggerScenarios":"Decoding a 64-bit varint field (timestamps, trace ID high bits, duration in thrift) where continuation bytes run past the 10-byte limit — typically because the reader started mid-field on garbage bytes.","commonSituations":"Misaligned reads after skipping an unknown field with a bad length; payloads that are not protobuf/thrift at all; storage blobs with flipped high bits (bit rot, bad base64 decoding).","solutions":["Use the reported position to verify alignment: check that the preceding tag and length prefix were parsed correctly.","Run the payload through protoc --decode (proto3) or a thrift inspector to find the first structural error.","Fix the upstream corruption (double-encoding, wrong charset, truncation) rather than the decoder.","In collectors, isolate bad messages to a dead-letter path and continue."],"exampleFix":"// before\n// fed arbitrary bytes straight into the decoder\nSpan span = SpanBytesDecoder.PROTO3.decodeOne(downloadBytes(url));\n\n// after\nbyte[] bytes = downloadBytes(url);\n// validate the magic shape first (field 1, length-delimited) then decode\nif (bytes.length < 2 || bytes[0] != 0x0a) throw new IllegalArgumentException(\"not a zipkin proto3 span\");\nSpan span = SpanBytesDecoder.PROTO3.decodeOne(bytes);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) { if (e.getMessage().contains(\"64-bit varint\")) { quarantine(bytes); return Optional.empty(); } throw e; }","preventionTips":["Detect >10-byte varint runs only happens with corruption — suspect alignment, not values.","Dead-letter malformed transport messages instead of retrying them."],"tags":["zipkin","varint","protobuf","malformed"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}