apache/druid · error · InvalidProtocolBufferException

Invalid Value type.

Error message

Invalid Value type.

What it means

google.protobuf.Value is a oneof that must have exactly one kind set (null_value, number_value, string_value, bool_value, struct_value, list_value). Druid's converter converts a Value message to a single value; when the message has more than one field populated it is malformed, so this InvalidProtocolBufferException is thrown.

Solutions

  1. Fix the producer to set exactly one field of the Value oneof
  2. Validate upstream bytes with protoc --decode before ingesting
  3. Check for data corruption in the transport (Kafka topic, network) that could merge or corrupt records

Example fix

// before: producer sets two members of the Value oneof
value.setStringValue("x"); value.setBoolValue(true);
// after: set exactly one
value.setStringValue("x");
Defensive patterns

Strategy: try-catch

Validate before calling

Message valueMsg = ...;
if ("google.protobuf.Value".equals(valueMsg.getDescriptorForType().getFullName())
    && valueMsg.getAllFields().size() > 1) {
  throw new IllegalStateException("google.protobuf.Value has multiple oneof members set");
}

Type guard

boolean isValidValue(Message msg) {
  if (!"google.protobuf.Value".equals(msg.getDescriptorForType().getFullName())) return true;
  int n = msg.getAllFields().size();
  return n == 0 || n == 1;
}

Try / catch

try {
  Map<String, Object> row = ProtobufConverter.convertMessage(msg);
} catch (ParseException e) {
  log.error("Malformed Value oneof in record; fix producer or skip record", e);
  // route to DLQ instead of failing the whole read
}

Prevention

When it happens

Trigger: A google.protobuf.Value message with two or more simultaneously-set oneof members is passed to ProtobufConverter.convertMessage (e.g. bytes crafted by hand or produced by a non-conformant producer); fields.size() > 1 at conversion time.

Common situations: Hand-crafted or fuzzed protobuf bytes; a buggy producer writing multiple oneof fields; binary data truncated/corrupted in transit causing malformed parse results.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/c3ee3101b5a91919. Report an issue: GitHub.

Appendix: source

Thrown at extensions-core/protobuf-extensions/src/main/java/org/apache/druid/data/input/protobuf/ProtobufConverter.java:218

        msg -> {
          final Descriptors.Descriptor descriptor = msg.getDescriptorForType();
          final Descriptors.FieldDescriptor field = descriptor.findFieldByName("fields");
          if (field == null) {
            throw new InvalidProtocolBufferException("Invalid Struct type.");
          }
          // Struct is formatted as a map object.
          return convertSingleValue(field, msg.getField(field));
        }
    );
    converters.put(
        Value.getDescriptor().getFullName(),
        msg -> {
          final Map<Descriptors.FieldDescriptor, Object> fields = msg.getAllFields();
          if (fields.isEmpty()) {
            return null;
          }
          if (fields.size() != 1) {
            throw new InvalidProtocolBufferException("Invalid Value type.");
          }
          final Map.Entry<Descriptors.FieldDescriptor, Object> entry = fields.entrySet().stream().findFirst().get();
          return convertSingleValue(entry.getKey(), entry.getValue());
        }
    );
    converters.put(
        ListValue.getDescriptor().getFullName(),
        msg -> {
          Descriptors.Descriptor descriptor = msg.getDescriptorForType();
          Descriptors.FieldDescriptor field = descriptor.findFieldByName("values");
          if (field == null) {
            throw new InvalidProtocolBufferException("Invalid ListValue type.");
          }
          return convertList(field, (List<?>) msg.getField(field));
        }
    );
    return converters;
  }

View on GitHub (pinned to 9b90983fd2)