grpc/grpc-java · error · IllegalArgumentException

Invalid input: expected span ID at offset ${pos}

Error message

Invalid input: expected span ID at offset ${pos}

What it means

After successfully parsing the trace ID, BinaryFormat.parseBytes expects the next byte to be the span-ID field ID (0x01) followed by an 8-byte span ID. This IllegalArgumentException is thrown when the byte at the current offset does not match SPAN_ID_FIELD_ID, indicating the serialized span context is not in the expected OpenTelemetry binary format.

Source

Thrown at opentelemetry/src/main/java/io/grpc/opentelemetry/BinaryFormat.java:133

      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));
      pos += ID_SIZE + SPAN_ID_SIZE;
    } else {
      throw new IllegalArgumentException("Invalid input: expected span ID at offset " + pos);
    }
    if (serialized.length > pos && serialized[pos] == TRACE_FLAG_FIELD_ID) {
      if (serialized.length < ALL_FORMAT_LENGTH) {
        throw new IllegalArgumentException("Invalid input: truncated");
      }
      traceFlags = TraceFlags.fromByte(serialized[pos + ID_SIZE]);
    }
    return SpanContext.create(traceId, spanId, traceFlags, TraceState.getDefault());
  }
}

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Ensure the writer serializes both trace ID (16 bytes) and span ID (8 bytes) fields with their field IDs in the OpenTelemetry binary format order.
  2. Check carrier/header size limits are not truncating the serialized span context before it reaches parseBytes.
  3. Validate byte-array length (at least 29 bytes for version + trace + span fields) before parsing.
  4. Catch IllegalArgumentException and fall back to an invalid/absent span context for graceful degradation.
Defensive patterns

Strategy: try-catch

Validate before calling

boolean hasSpanIdField(byte[] b) {
  // version(1) + fieldId(1) + traceId(16) + fieldId(1) = offset 19 must hold SPAN_ID_FIELD_ID (0x01)
  return b != null && b.length >= 20 && b[19] == 0x01;
}

Try / catch

try {
  ctx = BinaryFormat.parseBytes(bytes);
} catch (IllegalArgumentException e) {
  log.warn("malformed span context", e);
  ctx = SpanContext.getInvalid();
}

Prevention

When it happens

Trigger: Calling parseBytes with bytes where the span-ID field is missing, reordered, or replaced — e.g. a truncated payload containing version + trace ID but no span-ID field, or bytes written by a non-conforming encoder.

Common situations: Hand-rolled propagation serializers that emit only the trace ID, a truncated header due to size-limited metadata carriers, or version skew between writer and reader implementations of the binary format.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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