Skip to content

[BUG] MessageOneofEvaluator crashes with UnsupportedOperationException on repeated/map fields #427

@ospanoff

Description

@ospanoff

Description

MessageOneofEvaluator.evaluate() calls Message.hasField(field) on every field in its field list (MessageOneofEvaluator.java:54). In protobuf-java, hasField() throws UnsupportedOperationException when invoked on a repeated or map field because presence is not a concept that applies to them. If a MessageOneofRule references a repeated or map field by name, the evaluator will crash at runtime instead of producing a validation result.

Steps to Reproduce

  1. Define a protobuf message with at least one repeated (or map) field and a MessageOneofRule that includes that field:
    message Example {
      option (buf.validate.message).oneof = {
        fields: ["name", "tags"]
        required: true
      };
      string name = 1;
      repeated string tags = 2;
    }
  2. Build a Validator and validate any instance of Example.
  3. Observe the exception during evaluation.

Expected Behavior

The MessageOneofRule should work as documented — validating that at most one (or exactly one, if required) of the specified fields is set, regardless of whether the fields are singular, repeated, or map types.

Actual Behavior

An UnsupportedOperationException is thrown at runtime

Screenshots/Logs

java.lang.UnsupportedOperationException: hasField() called on a repeated field.
	at com.google.protobuf.GeneratedMessage.hasField(GeneratedMessage.java:255)
	at build.buf.protovalidate.MessageOneofEvaluator.evaluate(MessageOneofEvaluator.java:54)

Environment

  • Operating System: macOS
  • Version: Darwin 25.3.0
  • Compiler/Toolchain: JDK 21+, Gradle 9.3.1
  • Protobuf Compiler & Version: buf v1.66.0, protobuf-java 4.34.0
  • Protovalidate Version: v1.1.0

Possible Solution

In MessageOneofEvaluator.evaluate(), check whether the field is repeated before calling hasField(), and use an appropriate presence check instead:

for (FieldDescriptor field : fields) {
  boolean isSet = field.isRepeated()
      ? msg.getRepeatedFieldCount(field) > 0
      : msg.hasField(field);
  if (isSet) {
    hasCount++;
  }
}

Additional Context

The fix should be tested thoroughly across all protobuf field types — singular scalars, message fields, repeated fields, and map fields — to ensure MessageOneofEvaluator correctly determines presence for each.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions