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
- 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.
- Fix producers to use proper varint32 encoding (7 bits per byte, terminate at 5 bytes); prefer the shipped codecs.
- Watch for negative Java ints encoded as unsigned 64-bit varints — mask to 32 bits or use writeVarint64 where appropriate.
- 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
- Never encode negative ints as unsigned 64-bit varints into 32-bit fields.
- Reuse WriteBuffer/Proto3Fields writers instead of custom varint code.
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
- Greater than 64-bit varint at position {}
- Malformed: fieldNumber was zero at byte
- Malformed: invalid wireType
- Malformed: invalid boolean value at byte
- hex field greater than 32 chars long: {}
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/abb03da8e8a24fcc.
Report an issue: GitHub.