{"record":{"id":"0b5696ff88db0bd9","repo":"grpc/grpc-java","slug":"singlepredicate-must-have-either-value-match-or-cu","errorCode":null,"errorMessage":"SinglePredicate must have either value_match or custom_match","messagePattern":"SinglePredicate must have either value_match or custom_match","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/matcher/PredicateEvaluator.java","lineNumber":70,"sourceCode":"        throw new IllegalArgumentException(\"SinglePredicate must have input\");\n      }\n      this.input = UnifiedMatcher.resolveInput(proto.getInput());\n      \n      if (proto.hasValueMatch()) {\n        Matchers.StringMatcher stringMatcher =\n            MatcherParser.parseStringMatcher(proto.getValueMatch());\n        this.matcher = new StringMatcherAdapter(stringMatcher);\n      } else if (proto.hasCustomMatch()) {\n        TypedExtensionConfig customConfig = proto.getCustomMatch();\n        MatcherProvider provider = MatcherRegistry.getDefaultRegistry()\n            .getMatcherProvider(customConfig.getTypedConfig().getTypeUrl());\n        if (provider == null) {\n          throw new IllegalArgumentException(\"Unsupported custom_match matcher: \" \n              + customConfig.getTypedConfig().getTypeUrl());\n        }\n        this.matcher = provider.getMatcher(customConfig);\n      } else {\n        throw new IllegalArgumentException(\n            \"SinglePredicate must have either value_match or custom_match\");\n      }\n\n      if (!input.outputType().equals(matcher.inputType())) {\n        throw new IllegalArgumentException(\"Type mismatch: input \" + input.outputType().getName()\n            + \" not compatible with matcher \" + matcher.inputType().getName());\n      }\n    }\n    \n    @Override \n    boolean evaluate(MatchContext context) {\n      return matcher.match(input.apply(context));\n    }\n    \n\n\n    private static final class StringMatcherAdapter implements Matcher {\n      private final Matchers.StringMatcher stringMatcher;","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/matcher/PredicateEvaluator.java#L52-L88","documentation":"A SinglePredicate must specify exactly one of value_match or custom_match as its test condition. If neither is set, SinglePredicateEvaluator has no matcher to run and throws this IllegalArgumentException.","triggerScenarios":"Building a SinglePredicateEvaluator from a proto where hasValueMatch() is false and hasCustomMatch() is false — e.g. only the input was configured, or the match value block was deleted/never populated.","commonSituations":"Truncated or templated xDS configs; control-plane generators emitting input-only predicates; manual edits that removed the match condition while keeping the input.","solutions":["Populate value_match (StringMatcher: exact/prefix/regex/safe_regex etc.) or custom_match on the SinglePredicate","Validate hasValueMatch() || hasCustomMatch() during pre-parse config checks","Fix the config producer so every single_predicate carries a match condition"],"exampleFix":"// before\nsingle_predicate:\n  input:\n    typed_config:\n      '@type': type.googleapis.com/grpc.xds.Input.MyHeaderInput\n// after\nsingle_predicate:\n  input:\n    typed_config:\n      '@type': type.googleapis.com/grpc.xds.Input.MyHeaderInput\n  value_match:\n    exact: expected-value","handlingStrategy":"validation","validationCode":"if (!singlePredicate.hasValueMatch() && !singlePredicate.hasCustomMatch()) {\n  throw new IllegalArgumentException(\"single_predicate needs value_match or custom_match\");\n}","typeGuard":null,"tryCatchPattern":"try { new PredicateEvaluator.SinglePredicateEvaluator(proto); } catch (IllegalArgumentException e) { log.error(\"Invalid predicate config: \" + e.getMessage()); }","preventionTips":["Ensure every single_predicate sets one match condition","Validate generated configs with schema checks before push","Review config diffs for removed match blocks"],"tags":["xds","matcher","config-validation","grpc"],"backgroundTag":"missing-required-argument","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"}