{"record":{"id":"1d279ade1004c207","repo":"grpc/grpc-go","slug":"input-stringmatcher-proto-is-nil","errorCode":null,"errorMessage":"input StringMatcher proto is nil","messagePattern":"input StringMatcher proto is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/matcher/string_matcher.go","lineNumber":99,"sourceCode":"\t\treturn nil\n\t}\n\n\ts := new(string)\n\tif ignoreCase {\n\t\t*s = strings.ToLower(*input)\n\t} else {\n\t\t*s = *input\n\t}\n\treturn s\n}\n\n// StringMatcherFromProto is a helper function to create a StringMatcher from\n// the corresponding StringMatcher proto.\n//\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()","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/matcher/string_matcher.go#L81-L117","documentation":"Returned by StringMatcherFromProto (string_matcher.go:98-99) when the caller passes a nil *StringMatcher proto. The builder cannot derive a match pattern from a nil message, so it fails immediately rather than panicking on the subsequent GetMatchPattern switch.","triggerScenarios":"A header/path/rbac matcher configuration that references a StringMatcher field which was never populated, so the pointer passed to StringMatcherFromProto is nil. Commonly reached via newHeaderMatcher (StringMatch case) or newURLPathMatcher when the upstream proto field is unset.","commonSituations":"An xDS RBAC or route rule that declares a string matcher but leaves the matcher message empty; programmatic matcher construction that forwards an uninitialised proto field; control plane omitting the matcher body.","solutions":["Ensure the StringMatcher proto is fully populated (set exact/prefix/suffix/contains/safe_regex) before passing it in.","Null-check the matcher pointer at the call site and skip or fail with a clearer upstream error.","Fix the xDS/route configuration that produced an empty StringMatcher."],"exampleFix":"// before\nsm, err := matcher.StringMatcherFromProto(nil) // error\n// after\nif protoCfg == nil {\n    return errors.New(\"string_matcher must be configured\")\n}\nsm, err := matcher.StringMatcherFromProto(protoCfg)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isNonNilStringMatcher(m *v3matcherpb.StringMatcher) bool {\n    return m != nil\n}\n// guard the call site:\n//   if !isNonNilStringMatcher(sm) { return errors.New(\"string matcher required\") }","tryCatchPattern":null,"preventionTips":["Nil-check matcher protos before calling StringMatcherFromProto.","Validate xDS/route rules at publish time so empty matchers never reach the client.","Log the originating rule when a nil matcher is detected to locate the config gap."],"tags":["xds","matcher","rbac","config","nil-check"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}