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.
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 tagsView on GitHub (pinned to 878ce2a1fa)
Solutions
- 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).
- Verify the length-delimited prefix of the ID field is exactly 16 (0x10) for a 128-bit ID or 8 for 64-bit.
- Check the bytes are proto3 and not hex-encoded JSON IDs pasted into a binary field.
- 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
- Transport IDs as 8 or 16 binary bytes, never as hex text inside binary fields.
- Reject IDs that are not exactly 16 or 32 lowercase hex chars at ingest.
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
- Malformed: fieldNumber was zero at byte
- Malformed: invalid wireType
- Malformed: invalid boolean value at byte
- Greater than 32-bit varint at position {}
- Greater than 64-bit varint at position {}
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/b33758aef69b7a94.
Report an issue: GitHub.