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

  1. Ensure the propagating side serializes with the same gRPC OpenTelemetry binary format (version byte 0 first)
  2. Validate input length > 0 and serialized[0] == version before calling parseBytes
  3. 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

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


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/d71e07a4de86321a. Report an issue: GitHub.