{"record":{"id":"0de378836f99a4f9","repo":"grpc/grpc-java","slug":"stringmatcher-match-pattern-must-be-non-empty","errorCode":null,"errorMessage":"StringMatcher  (match_pattern) must be non-empty","messagePattern":"StringMatcher  \\(match_pattern\\) must be non-empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/MatcherParser.java","lineNumber":139,"sourceCode":"      case SUFFIX:\n        return Matchers.StringMatcher.forSuffix(\n            checkNonEmpty(proto.getSuffix(), \"suffix\"), proto.getIgnoreCase());\n      case SAFE_REGEX:\n        String regex = checkNonEmpty(proto.getSafeRegex().getRegex(), \"regex\");\n        return Matchers.StringMatcher.forSafeRegEx(Pattern.compile(regex));\n      case CONTAINS:\n        return Matchers.StringMatcher.forContains(\n            checkNonEmpty(proto.getContains(), \"contains\"), proto.getIgnoreCase());\n      case MATCHPATTERN_NOT_SET:\n      default:\n        throw new IllegalArgumentException(\n            \"Unknown StringMatcher match pattern: \" + proto.getMatchPatternCase());\n    }\n  }\n\n  private static String checkNonEmpty(String value, String name) {\n    if (value.isEmpty()) {\n      throw new IllegalArgumentException(\"StringMatcher \" + name \n          + \" (match_pattern) must be non-empty\");\n    }\n    return value;\n  }\n\n  /** Translates envoy proto FractionalPercent to internal FractionMatcher. */\n  public static Matchers.FractionMatcher parseFractionMatcher(\n      io.envoyproxy.envoy.type.v3.FractionalPercent proto) {\n    int denominator;\n    switch (proto.getDenominator()) {\n      case HUNDRED:\n        denominator = 100;\n        break;\n      case TEN_THOUSAND:\n        denominator = 10_000;\n        break;\n      case MILLION:\n        denominator = 1_000_000;","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/MatcherParser.java#L121-L157","documentation":"checkNonEmpty rejects StringMatcher values that are empty (e.g. an empty contains or exact value) with an IllegalArgumentException of the form 'StringMatcher <name> (match_pattern) must be non-empty'. The parser treats an empty match value as invalid config because it would match nothing meaningful.","triggerScenarios":"parseStringMatcher calls checkNonEmpty (e.g. for contains) and the proto field is set but holds an empty string.","commonSituations":"contains:\"\" or exact:\"\" in Envoy config generated by tooling; a field defaulting to empty after stripping whitespace; templating bug leaving a placeholder unfilled.","solutions":["Populate the match value with a non-empty string in the xDS config","Reject empty match values at the management server before distribution","Check for templating/config-generation bugs that emit empty values","If an empty match is intentional, use a different pattern type (e.g. prefix) if semantics allow"],"exampleFix":"// before\n{\"string_match\":{\"contains\":\"\"}}\n// after\n{\"string_match\":{\"contains\":\"session=\"}}","handlingStrategy":"validation","validationCode":"if (value == null || value.isEmpty()) { reject(name + \" must be non-empty\"); }","typeGuard":"null","tryCatchPattern":"try { matcher = MatcherParser.parseHeaderMatcher(proto); }\ncatch (IllegalArgumentException e) { if (e.getMessage().contains(\"must be non-empty\")) { fixConfigEntry(); } }","preventionTips":["Never emit empty match values from config tooling","Fill template placeholders; fail generation on empty values","Validate config fields server-side"],"tags":["xds","config","validation"],"backgroundTag":"empty-required-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"}