{"record":{"id":"4d8f75b597a14a0c","repo":"grpc/grpc-go","slug":"empty-suffix-is-not-allowed-in-stringmatcher","errorCode":null,"errorMessage":"empty suffix is not allowed in StringMatcher","messagePattern":"empty suffix is not allowed in StringMatcher","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/matcher/string_matcher.go","lineNumber":113,"sourceCode":"//\n// Returns a non-nil error if matcherProto is invalid.\nfunc StringMatcherFromProto(matcherProto *v3matcherpb.StringMatcher) (StringMatcher, error) {\n\tif matcherProto == nil {\n\t\treturn StringMatcher{}, errors.New(\"input StringMatcher proto is nil\")\n\t}\n\n\tmatcher := StringMatcher{ignoreCase: matcherProto.GetIgnoreCase()}\n\tswitch mt := matcherProto.GetMatchPattern().(type) {\n\tcase *v3matcherpb.StringMatcher_Exact:\n\t\tmatcher.exactMatch = newStrPtr(&mt.Exact, matcher.ignoreCase)\n\tcase *v3matcherpb.StringMatcher_Prefix:\n\t\tif matcherProto.GetPrefix() == \"\" {\n\t\t\treturn StringMatcher{}, errors.New(\"empty prefix is not allowed in StringMatcher\")\n\t\t}\n\t\tmatcher.prefixMatch = newStrPtr(&mt.Prefix, matcher.ignoreCase)\n\tcase *v3matcherpb.StringMatcher_Suffix:\n\t\tif matcherProto.GetSuffix() == \"\" {\n\t\t\treturn StringMatcher{}, errors.New(\"empty suffix is not allowed in StringMatcher\")\n\t\t}\n\t\tmatcher.suffixMatch = newStrPtr(&mt.Suffix, matcher.ignoreCase)\n\tcase *v3matcherpb.StringMatcher_SafeRegex:\n\t\tregex := matcherProto.GetSafeRegex().GetRegex()\n\t\tre, err := CompileSafeRegex(regex)\n\t\tif err != nil {\n\t\t\treturn StringMatcher{}, fmt.Errorf(\"safe_regex matcher %q is invalid\", regex)\n\t\t}\n\t\tmatcher = NewRegexStringMatcher(re)\n\tcase *v3matcherpb.StringMatcher_Contains:\n\t\tif matcherProto.GetContains() == \"\" {\n\t\t\treturn StringMatcher{}, errors.New(\"empty contains is not allowed in StringMatcher\")\n\t\t}\n\t\tmatcher.containsMatch = newStrPtr(&mt.Contains, matcher.ignoreCase)\n\tdefault:\n\t\treturn StringMatcher{}, fmt.Errorf(\"unrecognized string matcher: %+v\", matcherProto)\n\t}\n\treturn matcher, nil","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/matcher/string_matcher.go#L95-L131","documentation":"Symmetric to the prefix case: the Suffix variant of StringMatcher requires a non-empty suffix string. An empty suffix is rejected at string_matcher.go:112-113 because it would match every string and carries no information.","triggerScenarios":"Triggered when an xDS-supplied StringMatcher sets `suffix: \"\"`. Surfaces during decoding of header matchers, path matchers, or other StringMatcher-typed fields.","commonSituations":"Defaulted empty suffix in control-plane config; YAML `suffix:` with no value; an Envoy policy that used empty suffix as a placeholder; templating or serialization that emits empty strings.","solutions":["Set the suffix to a non-empty value (e.g. a domain like `.example.com`).","If the intent was catch-all, remove the matcher instead of using an empty suffix.","Fix the upstream config generator that produced the empty value."],"exampleFix":"// before\nsm, err := matcher.StringMatcherFromProto(&v3matcherpb.StringMatcher{\n    MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: \"\"},\n}) // err: empty suffix is not allowed\n\n// after\nsm, err := matcher.StringMatcherFromProto(&v3matcherpb.StringMatcher{\n    MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: \".example.com\"},\n})","handlingStrategy":"validation","validationCode":"func validateStringMatcherProto(p *v3matcherpb.StringMatcher) error {\n    if p == nil { return errors.New(\"nil StringMatcher\") }\n    if _, ok := p.GetMatchPattern().(*v3matcherpb.StringMatcher_Suffix); ok && p.GetSuffix() == \"\" {\n        return errors.New(\"StringMatcher.suffix must not be empty\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never emit `suffix: \"\"` — omit the matcher entirely for a catch-all.","Lint RBAC/route configs for empty suffix values in CI.","Use meaningful suffixes (e.g. domain names) and document examples for policy authors."],"tags":["grpc","xds","matcher","validation","suffix"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}