openzipkin/zipkin · error · IllegalArgumentException

hex field greater than 32 chars long

Error message

hex field greater than 32 chars long: {}

What it means

Zipkin IDs (trace/span/parent) are at most 16 bytes, i.e. 32 hex characters. ReadBuffer.readBytesAsHex converts fixed-length byte fields to hex and throws 'hex field greater than 32 chars long: N' when a length-delimited ID field in the payload is longer than 16 bytes — the decoder refuses impossible IDs rather than truncating.

Solutions

  1. On the producer, convert hex IDs to their 16-byte binary form before putting them into proto3/thrift fields (Zipkin never transports ID hex in binary fields).
  2. Verify the length-delimited prefix of the ID field is exactly 16 (0x10) for a 128-bit ID or 8 for 64-bit.
  3. Check the bytes are proto3 and not hex-encoded JSON IDs pasted into a binary field.
  4. Drop the malformed span and log the offending ID bytes for the producer team.

Example fix

// before
// sent the 32-char hex string as bytes (32 bytes)
field.write(b, span.traceId().getBytes(UTF_8));

// after
// send the 16-byte binary form; hex conversion happens on read
byte[] id = BufferUtil.lowerHexToUnsignedBytes(span.traceId());
field.write(b, id);
Defensive patterns

Strategy: validation

Validate before calling

// producer-side: verify ID hex length before binary conversion
byte[] toIdBytes(String hex) {
  if (hex.length() != 16 && hex.length() != 32) throw new IllegalArgumentException("bad id: " + hex);
  return zipkin2.internal.BufferUtil.lowerHexToUnsignedBytes(hex);
}

Type guard

boolean isValidTraceIdHex(String s) { return s != null && s.matches("[0-9a-f]{16}([0-9a-f]{16})?"); }

Prevention

When it happens

Trigger: PROTO3 (or thrift) decoding where a trace_id/span_id field carries more than 16 bytes — e.g. a 32-byte ID mistakenly sent as raw bytes instead of the 16-byte binary form, or a misread length prefix on an ID field.

Common situations: Producers that treat the 32-char hex string as bytes (32 bytes instead of 16); systems generating non-Zipkin 128-bit-plus identifiers; payload corruption shifting a length prefix.

Related errors


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

Appendix: source

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

  abstract int pos();

  abstract short readShort();

  abstract int readInt();

  abstract long readLong();

  abstract long readLongLe();

  @Override public final int read() {
    return available() > 0 ? readByteUnsafe() : -1;
  }

  final String readBytesAsHex(int length) {
    // All our hex fields are at most 32 characters.
    if (length > 32) {
      throw new IllegalArgumentException("hex field greater than 32 chars long: " + length);
    }

    require(length);
    char[] result = RecyclableBuffers.shortStringBuffer();
    int hexLength = length * 2;
    for (int i = 0; i < hexLength; i += 2) {
      byte b = readByteUnsafe();
      result[i + 0] = HEX_DIGITS[(b >> 4) & 0xf];
      result[i + 1] = HEX_DIGITS[b & 0xf];
    }
    return new String(result, 0, hexLength);
  }

  /**
   * @return the value read. Use {@link WriteBuffer#varintSizeInBytes(long)} to tell how many bytes.
   * @throws IllegalArgumentException if more than 64 bits were encoded
   */
  // included in the main api as this is used commonly, for example reading proto tags

View on GitHub (pinned to 878ce2a1fa)