{"record":{"id":"e856f18d4ab2c408","repo":"grpc/grpc-java","slug":"ormatcher-must-have-at-least-2-predicates","errorCode":null,"errorMessage":"OrMatcher must have at least 2 predicates","messagePattern":"OrMatcher must have at least 2 predicates","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/matcher/PredicateEvaluator.java","lineNumber":119,"sourceCode":"              \"StringMatcher expected a String input, but received: \" \n              + value.getClass().getName());\n        }\n        return stringMatcher.matches((String) value);\n      }\n\n      @Override\n      public Class<?> inputType() {\n        return String.class;\n      }\n    }\n  }\n  \n  private static final class OrMatcherEvaluator extends PredicateEvaluator {\n    private final List<PredicateEvaluator> evaluators;\n    \n    OrMatcherEvaluator(Predicate.PredicateList proto) {\n      if (proto.getPredicateCount() < 2) {\n        throw new IllegalArgumentException(\"OrMatcher must have at least 2 predicates\");\n      }\n      this.evaluators = new ArrayList<>(proto.getPredicateCount());\n      for (Predicate p : proto.getPredicateList()) {\n        evaluators.add(PredicateEvaluator.fromProto(p));\n      }\n    }\n    \n    @Override \n    boolean evaluate(MatchContext context) {\n      for (PredicateEvaluator e : evaluators) {\n        if (e.evaluate(context)) {\n          return true;\n        }\n      }\n      return false;\n    }\n  }\n","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/matcher/PredicateEvaluator.java#L101-L137","documentation":"An OrMatcherEvaluator represents a PredicateList under or_matcher; matching against zero or one predicate is meaningless (an OR of one term is that term). The constructor throws IllegalArgumentException when the proto has fewer than 2 predicates.","triggerScenarios":"Building OrMatcherEvaluator from a Predicate.PredicateList proto with getPredicateCount() < 2 — e.g. or_matcher set to an empty list, or a single-element list where the author should have used the predicate directly.","commonSituations":"Control-plane config generators emitting or_matcher with one clause; config simplification tools that stripped duplicate predicates; hand-written configs that over-nested a single condition into an or_matcher.","solutions":["Ensure or_matcher contains at least 2 predicates in the config","Replace single-predicate or_matcher usage with the predicate directly","Pre-validate PredicateList counts before parsing the matcher tree"],"exampleFix":"// before\nor_matcher:\n  predicate:\n  - single_predicate: { ... }\n// after: use the predicate directly, or add a second clause\nor_matcher:\n  predicate:\n  - single_predicate: { ... }\n  - single_predicate: { ... }","handlingStrategy":"validation","validationCode":"if (proto.getPredicateCount() < 2) {\n  throw new IllegalArgumentException(\"or_matcher requires >= 2 predicates\");\n}","typeGuard":null,"tryCatchPattern":"try { new PredicateEvaluator.OrMatcherEvaluator(proto); } catch (IllegalArgumentException e) { log.warn(\"or_matcher with <2 predicates: \" + e.getMessage()); }","preventionTips":["Collapse single-clause or_matchers into the predicate itself","Validate predicate list lengths on the control plane","Add config linting for minimum list sizes"],"tags":["xds","matcher","config-validation","grpc"],"backgroundTag":"value-out-of-range","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}