grpc/grpc-java · warning · IllegalArgumentException
Unsupported version.
Error message
Unsupported version.
What it means
BinaryFormat (the OpenTelemetry SpanContext propagator for gRPC) parses the binary propagation format, whose first byte must equal VERSION_ID. If the byte array is empty or starts with a different version byte, parseBytes throws IllegalArgumentException 'Unsupported version.'
Source
Thrown at opentelemetry/src/main/java/io/grpc/opentelemetry/BinaryFormat.java:112
public byte[] toBytes(SpanContext spanContext) {
checkNotNull(spanContext, "spanContext");
byte[] bytes = new byte[ALL_FORMAT_LENGTH];
bytes[VERSION_ID_OFFSET] = VERSION_ID;
bytes[TRACE_ID_FIELD_ID_OFFSET] = TRACE_ID_FIELD_ID;
System.arraycopy(spanContext.getTraceIdBytes(), 0, bytes, TRACE_ID_OFFSET, TRACE_ID_SIZE);
bytes[SPAN_ID_FIELD_ID_OFFSET] = SPAN_ID_FIELD_ID;
System.arraycopy(spanContext.getSpanIdBytes(), 0, bytes, SPAN_ID_OFFSET, SPAN_ID_SIZE);
bytes[TRACE_FLAG_FIELD_ID_OFFSET] = TRACE_FLAG_FIELD_ID;
bytes[TRACE_FLAG_OFFSET] = spanContext.getTraceFlags().asByte();
return bytes;
}
@Override
public SpanContext parseBytes(byte[] serialized) {
checkNotNull(serialized, "bytes");
if (serialized.length == 0 || serialized[0] != VERSION_ID) {
throw new IllegalArgumentException("Unsupported version.");
}
if (serialized.length < REQUIRED_FORMAT_LENGTH) {
throw new IllegalArgumentException("Invalid input: truncated");
}
String traceId;
String spanId;
TraceFlags traceFlags = TraceFlags.getDefault();
int pos = 1;
if (serialized[pos] == TRACE_ID_FIELD_ID) {
traceId = TraceId.fromBytes(
Arrays.copyOfRange(serialized, pos + ID_SIZE, pos + ID_SIZE + TRACE_ID_SIZE));
pos += ID_SIZE + TRACE_ID_SIZE;
} else {
throw new IllegalArgumentException("Invalid input: expected trace ID at offset " + pos);
}
if (serialized[pos] == SPAN_ID_FIELD_ID) {
spanId = SpanId.fromBytes(
Arrays.copyOfRange(serialized, pos + ID_SIZE, pos + ID_SIZE + SPAN_ID_SIZE));View on GitHub (pinned to 64daddc1f3)
Solutions
- Ensure the propagating side serializes with the same gRPC OpenTelemetry binary format (version byte 0 first)
- Validate input length > 0 and serialized[0] == version before calling parseBytes
- Align library versions between producer and consumer so the format matches
Example fix
// before
SpanContext ctx = propagator.parseBytes(carrierBytes);
// after
if (carrierBytes != null && carrierBytes.length > 0 && carrierBytes[0] == 0) { SpanContext ctx = propagator.parseBytes(carrierBytes); } Defensive patterns
Strategy: validation
Validate before calling
boolean isParsableSpanContext(byte[] b) { return b != null && b.length > 0 && b[0] == 0; } Try / catch
try { ctx = propagator.parseBytes(bytes); }
catch (IllegalArgumentException e) {
if (e.getMessage().equals("Unsupported version.")) { /* fall back to default SpanContext */ ctx = SpanContext.INVALID; }
} Prevention
- Use the library's toBytes()/parseBytes pair on both sides
- Pin matching opentelemetry/gRPC library versions across services
- Guard against empty carriers before parsing
When it happens
Trigger: Passing a zero-length byte array or a binary blob serialized with an unknown/different version prefix into OpenTelemetryContextStorage/BinaryFormat.parseBytes (e.g. from another propagator's carrier).
Common situations: Cross-service tracing with mismatched propagation format versions, manual tests feeding arbitrary bytes, carriers populated by a different tracing system.
Related errors
- Invalid input: truncated
- Address types of NameResolver '%s' for '%s' not supported by
- Could not find a NameResolverProvider for %s%s
- ${result.error}
- Invalid initial window size: ${newWindowSize}
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/d71e07a4de86321a.
Report an issue: GitHub.