openzipkin/zipkin · error · IllegalArgumentException

Greater than 32-bit varint at position {}

Error message

Greater than 32-bit varint at position {}

What it means

ReadBuffer.readVarint32 decodes up to 5 bytes; if the 5th byte still has high bits set beyond the 32-bit range ((b & 0xf0) != 0), it throws 'Greater than 32-bit varint at position P'. This means a 32-bit varint field in the payload was encoded with more than 32 bits of payload — corrupt data or a writer emitting 64-bit varints where 32-bit are expected.

Source

Thrown at zipkin/src/main/java/zipkin2/internal/ReadBuffer.java:351

    if ((b = readByte()) >= 0) {
      return result | b << 7;
    }
    result |= (b & 0x7f) << 7;

    if ((b = readByte()) >= 0) {
      return result | b << 14;
    }
    result |= (b & 0x7f) << 14;

    if ((b = readByte()) >= 0) {
      return result | b << 21;
    }
    result |= (b & 0x7f) << 21;

    b = readByte();
    if ((b & 0xf0) != 0) {
      throw new IllegalArgumentException("Greater than 32-bit varint at position " + (pos() - 1));
    }
    return result | b << 28;
  }

  final long readVarint64() {
    byte b; // negative number implies MSB set
    if ((b = readByte()) >= 0) {
      return b;
    }

    long result = b & 0x7f;
    for (int i = 1; b < 0 && i < 10; i++) {
      b = readByte();
      if (i == 9 && (b & 0xf0) != 0) {
        throw new IllegalArgumentException("Greater than 64-bit varint at position " + (pos() - 1));
      }
      result |= (long) (b & 0x7f) << (i * 7);
    }

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Dump the bytes from the reported position and count the varint's continuation bytes (high bit set) — more than 4 continuations means a bad encoder.
  2. Fix producers to use proper varint32 encoding (7 bits per byte, terminate at 5 bytes); prefer the shipped codecs.
  3. Watch for negative Java ints encoded as unsigned 64-bit varints — mask to 32 bits or use writeVarint64 where appropriate.
  4. Quarantine the message; this failure is deterministic per payload.

Example fix

// before
// naive: wrote int with 64-bit-style 10-byte varint
long v = someInt;
while ((v & ~0x7fL) != 0) { out.writeByte((int)(v & 0x7f) | 0x80); v >>>= 7; }
out.writeByte((int) v);

// after
// correct 32-bit varint, max 5 bytes
WriteBuffer b = ...; b.writeVarint(someInt);
Defensive patterns

Strategy: validation

Validate before calling

// producer-side encoder check: varint32 of a masked int always fits 5 bytes
void writeVarint32(WriteBuffer b, int v) { b.writeVarint(v); } // use library, never hand-roll

Try / catch

catch (IllegalArgumentException e) { if (e.getMessage().contains("32-bit varint")) dropAndAlertProducer(); else throw e; }

Prevention

When it happens

Trigger: Decoding proto3/thrift span fields like durations, timestamps, or length prefixes where the varint run does not terminate within 5 bytes with value bits only in the low 4 bits of the last byte.

Common situations: A hand-rolled encoder always writes 10-byte (64-bit style) varints; a sign-extension bug encoding a negative int as a huge varint; misaligned reads after an earlier bad field.

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/abb03da8e8a24fcc. Report an issue: GitHub.