{"record":{"id":"29e9aa904e44267e","repo":"grpc/grpc-java","slug":"matchertree-must-have-input","errorCode":null,"errorMessage":"MatcherTree must have input","messagePattern":"MatcherTree must have input","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/matcher/MatcherTree.java","lineNumber":43,"sourceCode":"import java.util.Map;\nimport java.util.function.Predicate;\nimport javax.annotation.Nullable;\n\nfinal class MatcherTree extends UnifiedMatcher {\n  private static final String TYPE_URL_HTTP_ATTRIBUTES_CEL_INPUT =\n      \"type.googleapis.com/xds.type.matcher.v3.HttpAttributesCelMatchInput\";\n  private final MatchInput input;\n  @Nullable \n  private final Map<String, OnMatch> exactMatchMap;\n  @Nullable \n  private final PrefixTrie prefixTrie;\n  @Nullable \n  private final OnMatch onNoMatch;\n  \n  MatcherTree(Matcher.MatcherTree proto, @Nullable Matcher.OnMatch onNoMatchProto,\n      Predicate<String> actionValidator) {\n    if (!proto.hasInput()) {\n      throw new IllegalArgumentException(\"MatcherTree must have input\");\n    }\n    if (proto.getInput().getTypedConfig().getTypeUrl()\n        .equals(TYPE_URL_HTTP_ATTRIBUTES_CEL_INPUT)) {\n      throw new IllegalArgumentException(\n          \"HttpAttributesCelMatchInput cannot be used with MatcherTree\");\n    }\n    \n    if (proto.hasCustomMatch()) {\n      throw new IllegalArgumentException(\"MatcherTree does not support custom_match\");\n    }\n    \n    this.input = UnifiedMatcher.resolveInput(proto.getInput());\n    \n    if (proto.hasExactMatchMap()) {\n      Matcher.MatcherTree.MatchMap matchMap = proto.getExactMatchMap();\n      if (matchMap.getMapCount() == 0) {\n        throw new IllegalArgumentException(\n            \"MatcherTree exact_match_map must contain at least one entry\");","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/matcher/MatcherTree.java#L25-L61","documentation":"A MatcherTree evaluates values produced by a single input source, so the proto must set the input field; without an input the tree has nothing to match on and the constructor rejects the config. This is an eager validation of the xDS Matcher.MatcherTree requirement that `input` be present.","triggerScenarios":"Constructing MatcherTree from a Matcher.MatcherTree proto where hasInput() is false (the input field was omitted).","commonSituations":"Hand-written or templated xDS matcher config missing the input block, or control-plane code building a MatcherTree programmatically without calling setInput.","solutions":["Set the input field (a TypedExtensionConfig such as HttpRequestHeaderMatchInput) on the MatcherTree proto.","Regenerate the config from the control plane ensuring input is populated.","If no input source is needed, use MatcherList instead of MatcherTree."],"exampleFix":"// before\n{\"matcher_tree\": {\"exact_match_map\": {...}}}\n// after\n{\"matcher_tree\": {\"input\": {\"typed_config\": {\"@type\": \".../HttpRequestHeaderMatchInput\", \"header_name\": \"x-key\"}}, \"exact_match_map\": {...}}}","handlingStrategy":"validation","validationCode":"if (!treeProto.hasInput()) {\n  throw new IllegalArgumentException(\"MatcherTree config missing input; refusing to build\");\n}","typeGuard":"boolean hasInput(Matcher.MatcherTree proto) {\n  return proto.hasInput();\n}","tryCatchPattern":"try {\n  matcherTree = new MatcherTree(proto, onNoMatch, validator);\n} catch (IllegalArgumentException e) {\n  logger.warn(\"invalid MatcherTree config: \" + e.getMessage());\n  throw new StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription(e.getMessage()));\n}","preventionTips":["Always set input on MatcherTree protos before sending","Validate matcher configs on the management server","Use schemas/linters for xDS matcher configs"],"tags":["xds","matcher","config-validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}